diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4ca7133b750854091da447d55e8f6cabd5ab506c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,74 @@
+# Built application files
+*.apk
+*.aar
+*.ap_
+*.aab
+# Files for the ART/Dalvik VM
+*.dex
+# Java class files
+*.class
+# Generated files
+bin/
+gen/
+out/
+#  Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+# Gradle files
+.gradle/
+build/
+# Local configuration file (sdk path, etc)
+local.properties
+# Proguard folder generated by Eclipse
+proguard/
+# Log Files
+*.log
+# Android Studio Navigation editor temp files
+.navigation/
+# Android Studio captures folder
+captures/
+# IntelliJ
+*.iml
+.idea/
+# .idea/workspace.xml
+# .idea/tasks.xml
+# .idea/gradle.xml
+# .idea/assetWizardSettings.xml
+# .idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+*.jks
+*.keystore
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+# Google Services (e.g. APIs or Firebase)
+google-services.json
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+# Version control
+vcs.xml
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+# MacOS
+.DS_Store
+# App Specific cases
+app/release/output.json
+.idea/codeStyles/
diff --git a/drip-android-observer-master/Android/.floo b/drip-android-observer-master/Android/.floo
new file mode 100644
index 0000000000000000000000000000000000000000..b918f1045dbf236f7058babb92efec56d69da692
--- /dev/null
+++ b/drip-android-observer-master/Android/.floo
@@ -0,0 +1,3 @@
+{
+    "url": "https://floobits.com/hampus/DRIPScanner"
+}
\ No newline at end of file
diff --git a/drip-android-observer-master/Android/.flooignore b/drip-android-observer-master/Android/.flooignore
new file mode 100644
index 0000000000000000000000000000000000000000..ed824d39aa14a15853835f1b12371ba1054c17c8
--- /dev/null
+++ b/drip-android-observer-master/Android/.flooignore
@@ -0,0 +1,6 @@
+extern
+node_modules
+tmp
+vendor
+.idea/workspace.xml
+.idea/misc.xml
diff --git a/drip-android-observer-master/Android/app/build.gradle b/drip-android-observer-master/Android/app/build.gradle
index d208798d2e2680b727b2606be341cc86868b7391..c11cf25c622eb7812522bac11df9eac678454ac5 100644
--- a/drip-android-observer-master/Android/app/build.gradle
+++ b/drip-android-observer-master/Android/app/build.gradle
@@ -51,6 +51,7 @@ dependencies {
     implementation 'com.android.support:support-fragment:' + support_version
     implementation 'com.google.android.gms:play-services-maps:17.0.0'
     implementation 'com.google.android.gms:play-services-location:17.1.0'
+    implementation 'org.osmdroid:osmdroid-android:6.1.14'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
     implementation 'org.bouncycastle:bcprov-jdk15to18:1.69'
     implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
diff --git a/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml b/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml
index 468171b3a0ec57f96af2800e590bb551a1c6555c..1943ab4f61956403248c398d371477013ea0eda4 100644
--- a/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml
+++ b/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml
@@ -5,6 +5,10 @@
 
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
@@ -19,6 +23,7 @@
         android:label="@string/app_name"
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
+        android:hardwareAccelerated="false"
         android:theme="@style/AppTheme"
         tools:replace="android:icon"
         tools:ignore="GoogleAppIndexingWarning">
@@ -50,6 +55,6 @@
         <!-- </activity> -->
         <meta-data
             android:name="com.google.android.geo.API_KEY"
-            android:value="@string/google_maps_key" />
+            android:value="AIzaSyALqZ0HRS1IiuivBxD6E7sBPSlvdYC_jQs" />
     </application>
 </manifest>
\ No newline at end of file
diff --git a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java
index 9b92798fd5977829b91d8036feac38b7cea7f7e3..c6588fafbf8feade22eb41aacdd3f83815905d55 100644
--- a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java
+++ b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java
@@ -1,242 +1,31 @@
-/*
- * Copyright (C) 2019 Intel Corporation
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- */
 package org.dripdronescanner.android.app;
 
 import android.Manifest;
+import android.content.Context;
 import android.content.pm.PackageManager;
-import android.graphics.Color;
 import android.os.Bundle;
-import android.util.Log;
-import android.util.Pair;
+import android.preference.PreferenceManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.app.ActivityCompat;
-import androidx.lifecycle.Observer;
-import androidx.lifecycle.ViewModelProviders;
+import androidx.core.content.ContextCompat;
 
-import com.google.android.gms.maps.CameraUpdateFactory;
-import com.google.android.gms.maps.GoogleMap;
 import com.google.android.gms.maps.OnMapReadyCallback;
 import com.google.android.gms.maps.SupportMapFragment;
-import com.google.android.gms.maps.model.BitmapDescriptorFactory;
-import com.google.android.gms.maps.model.CameraPosition;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.Marker;
-import com.google.android.gms.maps.model.MarkerOptions;
-import com.google.android.gms.maps.model.Polyline;
-import com.google.android.gms.maps.model.PolylineOptions;
 
-import org.dripdronescanner.android.data.AircraftObject;
-import org.dripdronescanner.android.data.LocationData;
-import org.dripdronescanner.android.data.SystemData;
-import org.dripdronescanner.android.data.Util;
+import org.dripdronescanner.android.R;
+import org.osmdroid.config.Configuration;
+import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
+import org.osmdroid.views.MapView;
 
-import java.util.Collection;
-import java.util.HashMap;
+import java.util.ArrayList;
 
-public class AircraftMapView extends SupportMapFragment implements OnMapReadyCallback, GoogleMap.OnMarkerClickListener {
-    private static final String TAG = "AircraftMapView";
-    private GoogleMap googleMap;
-    private AircraftViewModel model;
-
-    private final HashMap<AircraftObject, MapObserver> aircraftObservers = new HashMap<>();
-
-    private final Util.DiffObserver<AircraftObject> allAircraftObserver = new Util.DiffObserver<AircraftObject>() {
-        @Override
-        public void onAdded(Collection<AircraftObject> added) {
-            for (AircraftObject aircraftObject : added) {
-                trackAircraft(aircraftObject);
-            }
-        }
-
-        @Override
-        public void onRemoved(Collection<AircraftObject> removed) {
-            for (AircraftObject aircraftObject : removed) {
-                stopTrackingAircraft(aircraftObject);
-            }
-        }
-    };
-
-    private void trackAircraft(AircraftObject aircraftObject) {
-        MapObserver observer = new MapObserver(aircraftObject);
-        aircraftObservers.put(aircraftObject, observer);
-    }
-
-    private void stopTrackingAircraft(AircraftObject aircraftObject) {
-        MapObserver observer = aircraftObservers.remove(aircraftObject);
-        if (observer == null) return;
-        observer.stop();
-    }
-
-    private static final int DESIRED_ZOOM = 17;
-    private static final int ALLOWED_ZOOM_MARGIN = 2;
-
-    private void setupModel() {
-        if (getActivity() == null)
-            return;
-
-        model = ViewModelProviders.of(getActivity()).get(AircraftViewModel.class);
-
-        model.getAllAircraft().observe(getViewLifecycleOwner(), allAircraftObserver);
-        model.getActiveAircraft().observe(getViewLifecycleOwner(), new Observer<AircraftObject>() {
-            MapObserver last = null;
-
-            @Override
-            public void onChanged(@Nullable AircraftObject object) {
-                if (object == null || object.getLocation() == null || googleMap == null)
-                    return;
-                MapObserver observer = aircraftObservers.get(object);
-                if (observer == null)
-                    return;
-
-                if (object.getLocation().getLatitude() == 0.0 && object.getLocation().getLongitude() == 0.0)
-                    return;
-
-                LatLng ll = new LatLng(object.getLocation().getLatitude(), object.getLocation().getLongitude());
-                Log.i(TAG, "centering on " + object + " at " + ll);
-
-                if (last != null && last.marker != null) {
-                    last.marker.setAlpha(0.5f);
-                    if (last.markerPilot != null)
-                        last.markerPilot.setAlpha(0.5f);
-                }
-                if (observer.marker != null)
-                    observer.marker.setAlpha(1.0f);
-                if (observer.markerPilot != null)
-                    observer.markerPilot.setAlpha(1.0f);
-
-                last = observer;
-
-                CameraPosition position = googleMap.getCameraPosition();
-                if (position.zoom < DESIRED_ZOOM - ALLOWED_ZOOM_MARGIN || position.zoom > DESIRED_ZOOM + ALLOWED_ZOOM_MARGIN)
-                    googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(ll, DESIRED_ZOOM));
-                else
-                    googleMap.moveCamera(CameraUpdateFactory.newLatLng(ll));
-            }
-        });
-    }
-
-    @Override
-    public boolean onMarkerClick(Marker marker) {
-
-        if (marker != null) {
-            Object tag = marker.getTag();
-            if (tag instanceof AircraftObject) {
-                model.setActiveAircraft((AircraftObject) tag);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    class MapObserver implements Observer<LocationData> {
-        private Marker marker;
-        private Marker markerPilot;
-        private Polyline polyline;
-        private PolylineOptions polylineOptions;
-
-        private final AircraftObject aircraft;
-
-        MapObserver(AircraftObject active) {
-            aircraft = active;
-            aircraft.location.observe(AircraftMapView.this, this);
-            aircraft.system.observe(AircraftMapView.this, systemObserver);
-            polylineOptions = new PolylineOptions()
-                    .color(Color.RED)
-                    .clickable(true);
-        }
-
-        void stop() {
-            aircraft.location.removeObserver(this);
-            aircraft.system.removeObserver(systemObserver);
-            if (marker != null) {
-                marker.remove();
-                marker = null;
-            }
-            if (markerPilot != null) {
-                markerPilot.remove();
-                markerPilot = null;
-            }
-            if (polyline != null) {
-                polyline.remove();
-                polyline = null;
-            }
-            polylineOptions = null;
-        }
-
-        private final Observer<SystemData> systemObserver = new Observer<SystemData>() {
-            @Override
-            public void onChanged(@Nullable SystemData ignore) {
-                SystemData sys = aircraft.getSystem();
-                if (sys == null || googleMap == null)
-                    return;
-
-                // filter out zero data
-                if (sys.getOperatorLatitude() == 0.0 && sys.getOperatorLongitude() == 0.0)
-                    return;
-
-                LatLng latLng = new LatLng(sys.getOperatorLatitude(), sys.getOperatorLongitude());
-                if (markerPilot == null) {
-                    String id = "ID missing";
-                    if (aircraft.getIdentification() != null)
-                        id = aircraft.getIdentification().getUasIdAsString();
-                    markerPilot = googleMap.addMarker(
-                            new MarkerOptions()
-                                    .alpha(0.5f)
-                                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
-                                    .position(latLng)
-                                    .title("pilot " + id));
-                    markerPilot.setTag(new Pair<>(aircraft, this));
-                }
-                markerPilot.setPosition(latLng);
-            }
-        };
-
-        @Override
-        public void onChanged(@Nullable LocationData ignore) {
-            boolean zoom = false;
-            LocationData loc = aircraft.getLocation();
-            if (loc == null || googleMap == null || polylineOptions == null)
-                return;
-
-            // filter out zero data
-            if (loc.getLatitude() == 0.0 && loc.getLongitude() == 0.0)
-                return;
-
-            LatLng latLng = new LatLng(loc.getLatitude(), loc.getLongitude());
-            if (marker == null) {
-                String id = "ID missing";
-                if (aircraft.getIdentification() != null)
-                    id = aircraft.getIdentification().getUasIdAsString();
-                marker = googleMap.addMarker(
-                        new MarkerOptions()
-                                .alpha(0.5f)
-                                .position(latLng)
-                                .title("aircraft " + id));
-                marker.setTag(aircraft);
-                zoom = true;
-            }
-
-            polylineOptions.add(latLng);
-            if (polyline != null) {
-                polyline.remove();
-                polyline = null;
-            }
-            polyline = googleMap.addPolyline(polylineOptions);
-
-            marker.setPosition(latLng);
-            if (zoom) {
-                googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
-            }
-        }
-    }
+public class AircraftMapView extends SupportMapFragment implements OnMapReadyCallback {
+    private final int REQUEST_PERMISSIONS_REQUEST_CODE = 1;
+    private MapView map = null;
 
     @Override
     public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle bundle) {
@@ -246,34 +35,84 @@ public class AircraftMapView extends SupportMapFragment implements OnMapReadyCal
     }
 
     @Override
-    public void onActivityCreated(Bundle bundle) {
-        super.onActivityCreated(bundle);
-        setupModel();
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        //handle permissions first, before map is created. not depicted here
+
+        //load/initialize the osmdroid configuration, this can be done 
+        Context ctx = getApplicationContext();
+        Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
+        //setting this before the layout is inflated is a good idea
+        //it 'should' ensure that the map has a writable location for the map cache, even without permissions
+        //if no tiles are displayed, you can try overriding the cache path using Configuration.getInstance().setCachePath
+        //see also StorageUtils
+        //note, the load method also sets the HTTP User Agent to your application's package name, abusing osm's
+        //tile servers will get you banned based on this string
+
+        //inflate and create the map
+        setContentView(R.layout.activity_main);
+
+        map = (MapView) findViewById(R.id.map_view);
+        map.setTileSource(TileSourceFactory.MAPNIK);
+
+        requestPermissionsIfNecessary(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}
+                //arrayOf(
+                // if you need to show the current location, uncomment the line below
+                // Manifest.permission.ACCESS_FINE_LOCATION,
+                // WRITE_EXTERNAL_STORAGE is required in order to show the map
+                //Manifest.permission.WRITE_EXTERNAL_STORAGE
+        );
     }
 
     @Override
-    public void onMapReady(GoogleMap googleMap) {
-        if (getActivity() == null)
-            return;
+    public void onResume() {
+        super.onResume();
+        //this will refresh the osmdroid configuration on resuming.
+        //if you make changes to the configuration, use 
+        //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+        //Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this));
+        map.onResume(); //needed for compass, my location overlays, v6.0.0 and up
+    }
 
-        this.googleMap = googleMap;
+    @Override
+    public void onPause() {
+        super.onPause();
+        //this will refresh the osmdroid configuration on resuming.
+        //if you make changes to the configuration, use 
+        //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+        //Configuration.getInstance().save(this, prefs);
+        map.onPause();  //needed for compass, my location overlays, v6.0.0 and up
+    }
 
-        if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
-            ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
-            // TODO: Consider calling ActivityCompat#requestPermissions
-            // to request the missing permissions, and then overriding
-            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
-            //                                          int[] grantResults)
-            // to handle the case where the user grants the permission. See the documentation
-            // for ActivityCompat#requestPermissions for more details.
-            Log.e("XX", "##################### can't make the right permissions");
-            return;
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+        ArrayList<String> permissionsToRequest = new ArrayList<>();
+        for (int i = 0; i < grantResults.length; i++) {
+            permissionsToRequest.add(permissions[i]);
         }
+        if (permissionsToRequest.size() > 0) {
+            ActivityCompat.requestPermissions(
+                    this,
+                    permissionsToRequest.toArray(new String[0]),
+                    REQUEST_PERMISSIONS_REQUEST_CODE);
+        }
+    }
 
-        googleMap.getUiSettings().setMyLocationButtonEnabled(true);
-        googleMap.getUiSettings().setMapToolbarEnabled(false);
-        googleMap.setMyLocationEnabled(true);
-        googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
-        googleMap.setOnMarkerClickListener(this);
+    private void requestPermissionsIfNecessary(String[] permissions) {
+        ArrayList<String> permissionsToRequest = new ArrayList<>();
+        for (String permission : permissions) {
+            if (ContextCompat.checkSelfPermission(this, permission)
+                    != PackageManager.PERMISSION_GRANTED) {
+                // Permission is not granted
+                permissionsToRequest.add(permission);
+            }
+        }
+        if (permissionsToRequest.size() > 0) {
+            ActivityCompat.requestPermissions(
+                    this,
+                    permissionsToRequest.toArray(new String[0]),
+                    REQUEST_PERMISSIONS_REQUEST_CODE);
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapViewOld.java b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapViewOld.java
new file mode 100644
index 0000000000000000000000000000000000000000..db4db206c05fda314d5f1a74823e6bac86c211ee
--- /dev/null
+++ b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapViewOld.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+package org.dripdronescanner.android.app;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+import androidx.lifecycle.Observer;
+import androidx.lifecycle.ViewModelProviders;
+
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.SupportMapFragment;
+import com.google.android.gms.maps.model.BitmapDescriptorFactory;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.MarkerOptions;
+import com.google.android.gms.maps.model.Polyline;
+import com.google.android.gms.maps.model.PolylineOptions;
+
+import org.dripdronescanner.android.data.AircraftObject;
+import org.dripdronescanner.android.data.LocationData;
+import org.dripdronescanner.android.data.SystemData;
+import org.dripdronescanner.android.data.Util;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+public class AircraftMapViewOld extends SupportMapFragment implements OnMapReadyCallback, GoogleMap.OnMarkerClickListener {
+    private static final String TAG = "AircraftMapView";
+    private GoogleMap googleMap;
+    private AircraftViewModel model;
+
+    private final HashMap<AircraftObject, MapObserver> aircraftObservers = new HashMap<>();
+
+    private final Util.DiffObserver<AircraftObject> allAircraftObserver = new Util.DiffObserver<AircraftObject>() {
+        @Override
+        public void onAdded(Collection<AircraftObject> added) {
+            for (AircraftObject aircraftObject : added) {
+                trackAircraft(aircraftObject);
+            }
+        }
+
+        @Override
+        public void onRemoved(Collection<AircraftObject> removed) {
+            for (AircraftObject aircraftObject : removed) {
+                stopTrackingAircraft(aircraftObject);
+            }
+        }
+    };
+
+    private void trackAircraft(AircraftObject aircraftObject) {
+        MapObserver observer = new MapObserver(aircraftObject);
+        aircraftObservers.put(aircraftObject, observer);
+    }
+
+    private void stopTrackingAircraft(AircraftObject aircraftObject) {
+        MapObserver observer = aircraftObservers.remove(aircraftObject);
+        if (observer == null) return;
+        observer.stop();
+    }
+
+    private static final int DESIRED_ZOOM = 17;
+    private static final int ALLOWED_ZOOM_MARGIN = 2;
+
+    private void setupModel() {
+        if (getActivity() == null)
+            return;
+
+        model = ViewModelProviders.of(getActivity()).get(AircraftViewModel.class);
+
+        model.getAllAircraft().observe(getViewLifecycleOwner(), allAircraftObserver);
+        model.getActiveAircraft().observe(getViewLifecycleOwner(), new Observer<AircraftObject>() {
+            MapObserver last = null;
+
+            @Override
+            public void onChanged(@Nullable AircraftObject object) {
+                if (object == null || object.getLocation() == null || googleMap == null)
+                    return;
+                MapObserver observer = aircraftObservers.get(object);
+                if (observer == null)
+                    return;
+
+                if (object.getLocation().getLatitude() == 0.0 && object.getLocation().getLongitude() == 0.0)
+                    return;
+
+                LatLng ll = new LatLng(object.getLocation().getLatitude(), object.getLocation().getLongitude());
+                Log.i(TAG, "centering on " + object + " at " + ll);
+
+                if (last != null && last.marker != null) {
+                    last.marker.setAlpha(0.5f);
+                    if (last.markerPilot != null)
+                        last.markerPilot.setAlpha(0.5f);
+                }
+                if (observer.marker != null)
+                    observer.marker.setAlpha(1.0f);
+                if (observer.markerPilot != null)
+                    observer.markerPilot.setAlpha(1.0f);
+
+                last = observer;
+
+                CameraPosition position = googleMap.getCameraPosition();
+                if (position.zoom < DESIRED_ZOOM - ALLOWED_ZOOM_MARGIN || position.zoom > DESIRED_ZOOM + ALLOWED_ZOOM_MARGIN)
+                    googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(ll, DESIRED_ZOOM));
+                else
+                    googleMap.moveCamera(CameraUpdateFactory.newLatLng(ll));
+            }
+        });
+    }
+
+    @Override
+    public boolean onMarkerClick(Marker marker) {
+
+        if (marker != null) {
+            Object tag = marker.getTag();
+            if (tag instanceof AircraftObject) {
+                model.setActiveAircraft((AircraftObject) tag);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    class MapObserver implements Observer<LocationData> {
+        private Marker marker;
+        private Marker markerPilot;
+        private Polyline polyline;
+        private PolylineOptions polylineOptions;
+
+        private final AircraftObject aircraft;
+
+        MapObserver(AircraftObject active) {
+            aircraft = active;
+            aircraft.location.observe(AircraftMapViewOld.this, this);
+            aircraft.system.observe(AircraftMapViewOld.this, systemObserver);
+            polylineOptions = new PolylineOptions()
+                    .color(Color.RED)
+                    .clickable(true);
+        }
+
+        void stop() {
+            aircraft.location.removeObserver(this);
+            aircraft.system.removeObserver(systemObserver);
+            if (marker != null) {
+                marker.remove();
+                marker = null;
+            }
+            if (markerPilot != null) {
+                markerPilot.remove();
+                markerPilot = null;
+            }
+            if (polyline != null) {
+                polyline.remove();
+                polyline = null;
+            }
+            polylineOptions = null;
+        }
+
+        private final Observer<SystemData> systemObserver = new Observer<SystemData>() {
+            @Override
+            public void onChanged(@Nullable SystemData ignore) {
+                SystemData sys = aircraft.getSystem();
+                if (sys == null || googleMap == null)
+                    return;
+
+                // filter out zero data
+                if (sys.getOperatorLatitude() == 0.0 && sys.getOperatorLongitude() == 0.0)
+                    return;
+
+                LatLng latLng = new LatLng(sys.getOperatorLatitude(), sys.getOperatorLongitude());
+                if (markerPilot == null) {
+                    String id = "ID missing";
+                    if (aircraft.getIdentification() != null)
+                        id = aircraft.getIdentification().getUasIdAsString();
+                    markerPilot = googleMap.addMarker(
+                            new MarkerOptions()
+                                    .alpha(0.5f)
+                                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
+                                    .position(latLng)
+                                    .title("pilot " + id));
+                    markerPilot.setTag(new Pair<>(aircraft, this));
+                }
+                markerPilot.setPosition(latLng);
+            }
+        };
+
+        @Override
+        public void onChanged(@Nullable LocationData ignore) {
+            boolean zoom = false;
+            LocationData loc = aircraft.getLocation();
+            if (loc == null || googleMap == null || polylineOptions == null)
+                return;
+
+            // filter out zero data
+            if (loc.getLatitude() == 0.0 && loc.getLongitude() == 0.0)
+                return;
+
+            LatLng latLng = new LatLng(loc.getLatitude(), loc.getLongitude());
+            if (marker == null) {
+                String id = "ID missing";
+                if (aircraft.getIdentification() != null)
+                    id = aircraft.getIdentification().getUasIdAsString();
+                marker = googleMap.addMarker(
+                        new MarkerOptions()
+                                .alpha(0.5f)
+                                .position(latLng)
+                                .title("aircraft " + id));
+                marker.setTag(aircraft);
+                zoom = true;
+            }
+
+            polylineOptions.add(latLng);
+            if (polyline != null) {
+                polyline.remove();
+                polyline = null;
+            }
+            polyline = googleMap.addPolyline(polylineOptions);
+
+            marker.setPosition(latLng);
+            if (zoom) {
+                googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
+            }
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle bundle) {
+        View view = super.onCreateView(layoutInflater, viewGroup, bundle);
+        getMapAsync(this);
+        return view;
+    }
+
+    @Override
+    public void onActivityCreated(Bundle bundle) {
+        super.onActivityCreated(bundle);
+        setupModel();
+    }
+
+    @Override
+    public void onMapReady(GoogleMap googleMap) {
+        if (getActivity() == null)
+            return;
+
+        this.googleMap = googleMap;
+
+        if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
+            ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+            // TODO: Consider calling ActivityCompat#requestPermissions
+            // to request the missing permissions, and then overriding
+            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            //                                          int[] grantResults)
+            // to handle the case where the user grants the permission. See the documentation
+            // for ActivityCompat#requestPermissions for more details.
+            Log.e("XX", "##################### can't make the right permissions");
+            return;
+        }
+
+        googleMap.getUiSettings().setMyLocationButtonEnabled(true);
+        googleMap.getUiSettings().setMapToolbarEnabled(false);
+        googleMap.setMyLocationEnabled(true);
+        googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
+        googleMap.setOnMarkerClickListener(this);
+    }
+}
diff --git a/drip-android-observer-master/Android/app/src/main/res/layout/activity_main.xml b/drip-android-observer-master/Android/app/src/main/res/layout/activity_main.xml
index 4e0822c3789deb978e37722b46c5cc3abcd802b2..284b2661836aecdbc17f5bf58b0e69714511338b 100644
--- a/drip-android-observer-master/Android/app/src/main/res/layout/activity_main.xml
+++ b/drip-android-observer-master/Android/app/src/main/res/layout/activity_main.xml
@@ -12,13 +12,21 @@
 	android:layout_height="match_parent"
 	tools:context=".MainActivity">
 
-	<com.google.android.gms.maps.MapView
+	<!--<com.google.android.gms.maps.MapView
 		android:id="@+id/map_view"
 		android:layout_width="wrap_content"
 		android:layout_height="wrap_content"
 		android:layout_marginTop="0dp"
 		app:layout_constraintLeft_toLeftOf="parent"
 		app:layout_constraintRight_toRightOf="parent"
-		app:layout_constraintTop_toTopOf="parent"></com.google.android.gms.maps.MapView>
+		app:layout_constraintTop_toTopOf="parent"></com.google.android.gms.maps.MapView>-->
+	<org.osmdroid.views.MapView
+		android:id="@+id/map_view"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_marginTop="0dp"
+		app:layout_constraintLeft_toLeftOf="parent"
+		app:layout_constraintRight_toRightOf="parent"
+		app:layout_constraintTop_toTopOf="parent"/>
 
 </androidx.constraintlayout.widget.ConstraintLayout>