Show station track together with info window

master
sh123 2022-09-04 15:26:59 +03:00
rodzic 4dcd4c5c4c
commit 7968612cf2
7 zmienionych plików z 91 dodań i 42 usunięć

Wyświetl plik

@ -39,6 +39,7 @@ dependencies {
implementation 'com.github.mik3y:usb-serial-for-android:3.4.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.lifecycle:lifecycle-livedata:2.5.1'
testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'

Wyświetl plik

@ -44,11 +44,13 @@ import org.osmdroid.views.overlay.Polygon;
import org.osmdroid.views.overlay.Polyline;
import org.osmdroid.views.overlay.compass.CompassOverlay;
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider;
import org.osmdroid.views.overlay.infowindow.MarkerInfoWindow;
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@ -57,22 +59,24 @@ public class MapActivity extends AppCompatActivity {
private MapView _map;
private IMapController _mapController;
private CompassOverlay _compassOverlay;
private MyLocationNewOverlay _myLocationNewOverlay;
private final HashMap<String, Marker> _objectOverlayItems = new HashMap<>();
private final HashMap<String, Polygon> _objectOverlayRangeCircles = new HashMap<>();
private StationItemViewModel _stationItemViewModel;
private PositionItemViewModel _positionItemViewModel;
private AprsSymbolTable _aprsSymbolTable;
private MarkerInfoWindow _infoWindow;
private String _mySymbolCode;
// live settings
private boolean _rotateMap = false;
private boolean _showCircles = false;
private LiveData<List<PositionItem>> _stationTrack;
List<GeoPoint> _stationTrackPoints = new ArrayList<>();
Polyline _stationTrackLine = new Polyline(); //see note below!
// stations and circles
private final HashMap<String, Marker> _objectOverlayItems = new HashMap<>();
private final HashMap<String, Polygon> _objectOverlayRangeCircles = new HashMap<>();
// track
private LiveData<List<PositionItem>> _activeTrackLiveData;
private final HashSet<Long> _activeTrackTimestamps = new HashSet<>();
private final List<GeoPoint> _activeTrackPoints = new ArrayList<>();
private final Polyline _activeTrackLine = new Polyline();
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -88,12 +92,13 @@ public class MapActivity extends AppCompatActivity {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
_aprsSymbolTable = AprsSymbolTable.getInstance(context);
_mySymbolCode = sharedPreferences.getString(PreferenceKeys.APRS_SYMBOL, "/[");
String mySymbolCode = sharedPreferences.getString(PreferenceKeys.APRS_SYMBOL, "/[");
// map
_map = findViewById(R.id.map);
_map.setTileSource(TileSourceFactory.MAPNIK);
_map.setMultiTouchControls(true);
_infoWindow = new MarkerInfoWindow(R.layout.bonuspack_bubble, _map);
// controller
_mapController = _map.getController();
@ -109,13 +114,13 @@ public class MapActivity extends AppCompatActivity {
super.onSensorChanged(sensorEvent);
}
};
_compassOverlay = new CompassOverlay(context, compassOrientationProvider, _map);
_compassOverlay.enableCompass();
_map.getOverlays().add(_compassOverlay);
CompassOverlay compassOverlay = new CompassOverlay(context, compassOrientationProvider, _map);
compassOverlay.enableCompass();
_map.getOverlays().add(compassOverlay);
// my location
_myLocationNewOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(context), _map);
Bitmap myBitmapIcon = _aprsSymbolTable.bitmapFromSymbol(_mySymbolCode, true);
Bitmap myBitmapIcon = _aprsSymbolTable.bitmapFromSymbol(mySymbolCode, true);
_myLocationNewOverlay.setDirectionIcon(myBitmapIcon);
_myLocationNewOverlay.setPersonIcon(myBitmapIcon);
@ -131,27 +136,27 @@ public class MapActivity extends AppCompatActivity {
_positionItemViewModel = new ViewModelProvider(this).get(PositionItemViewModel.class);
// station items, add data listener
_stationItemViewModel = new ViewModelProvider(this).get(StationItemViewModel.class);
StationItemViewModel _stationItemViewModel = new ViewModelProvider(this).get(StationItemViewModel.class);
// FIXME, room livedata sends all list if one item changed event with distinctUntilChanged
_stationItemViewModel.getAllStationItems().observe(this, allStations -> {
Log.i(TAG, "add stations " + allStations.size());
for (StationItem station : allStations) {
//Log.i(TAG, "new position " + station.getLatitude() + " " + station.getLongitude());
// do not add items without coordinate
if (station.getMaidenHead() == null) continue;
if (addStationPositionIcon(station)) {
addRangeCircle(station);
} else {
Log.e(TAG, "Failed to add APRS icon for " + station.getSrcCallsign() + ", " + station.getSymbolCode());
}
}
});
// add track
Paint p = _stationTrackLine.getOutlinePaint();
Paint p = _activeTrackLine.getOutlinePaint();
p.setStrokeWidth(8);
p.setColor(Color.RED);
p.setStyle(Paint.Style.STROKE);
p.setPathEffect(new DashPathEffect(new float[] {10f, 10f}, 0f));
_map.getOverlayManager().add(_stationTrackLine);
_map.getOverlayManager().add(_activeTrackLine);
}
@Override
@ -194,21 +199,41 @@ public class MapActivity extends AppCompatActivity {
}
private void addTrack(List<PositionItem> positions) {
boolean shouldSet = false;
for (PositionItem trackPoint : positions) {
//Log.i(TAG, "addPoint " + trackPoint.getLatitude() + " " + trackPoint.getLongitude());
_stationTrackPoints.add(new GeoPoint(trackPoint.getLatitude(), trackPoint.getLongitude()));
if (!_activeTrackTimestamps.contains(trackPoint.getTimestampEpoch())) {
Log.i(TAG, "addPoint " + trackPoint.getTimestampEpoch() + " " + trackPoint.getLatitude() + " " + trackPoint.getLongitude());
GeoPoint point = new GeoPoint(trackPoint.getLatitude(), trackPoint.getLongitude());
_activeTrackPoints.add(point);
_activeTrackTimestamps.add(trackPoint.getTimestampEpoch());
shouldSet = true;
}
}
_stationTrackLine.setPoints(_stationTrackPoints);
if (shouldSet)
_activeTrackLine.setPoints(_activeTrackPoints);
}
private boolean addStationPositionIcon(StationItem group) {
String callsign = group.getSrcCallsign();
Marker marker = null;
String newTitle = DateTools.epochToIso8601(group.getTimestampEpoch()) + " " + callsign;
String newSnippet = getStatus(group);
// find old marker
if (_objectOverlayItems.containsKey(callsign)) {
marker = _objectOverlayItems.get(callsign);
assert marker != null;
// skip if unchanged
GeoPoint oldPosition = marker.getPosition();
if (oldPosition.getLatitude() == group.getLatitude() &&
oldPosition.getLongitude() == group.getLongitude() &&
marker.getTitle().equals(newTitle) &&
marker.getSnippet().equals(newSnippet)) {
return false;
}
}
// create new marker
@ -274,25 +299,28 @@ public class MapActivity extends AppCompatActivity {
marker.setId(callsign);
marker.setIcon(drawableText);
marker.setImage(drawableInfoIcon);
/*
marker.setOnMarkerClickListener((monitoredMarker, mapView) -> {
if (_stationTrack != null)
_stationTrack.removeObservers(this);
_map.getOverlays().remove(_stationTrackLine);
_stationTrackPoints.clear();
_stationTrackLine.setPoints(_stationTrackPoints);
_map.getOverlays().add(_stationTrackLine);
_stationTrack = _positionItemViewModel.getPositionItems(monitoredMarker.getId());
_stationTrack.observe(this, this::addTrack);
GeoPoint markerPoint = monitoredMarker.getPosition();
_infoWindow.open(monitoredMarker, new GeoPoint(markerPoint.getLatitude(), markerPoint.getLongitude()), 0, -2*height);
if (_activeTrackLiveData != null)
_activeTrackLiveData.removeObservers(this);
_map.getOverlays().remove(_activeTrackLine);
_activeTrackPoints.clear();
_activeTrackTimestamps.clear();
_activeTrackLine.setPoints(_activeTrackPoints);
_map.getOverlays().add(_activeTrackLine);
// FIXME, room livedata sends all list if one item changed event with distinctUntilChanged
_activeTrackLiveData = _positionItemViewModel.getPositionItems(monitoredMarker.getId());
_activeTrackLiveData.observe(this, this::addTrack);
return false;
});
*/
_map.getOverlays().add(marker);
_objectOverlayItems.put(callsign, marker);
}
marker.setPosition(new GeoPoint(group.getLatitude(), group.getLongitude()));
marker.setTitle(DateTools.epochToIso8601(group.getTimestampEpoch()) + " " + callsign);
marker.setSnippet(getStatus(group));
marker.setTitle(newTitle);
marker.setSnippet(newSnippet);
return true;
}

Wyświetl plik

@ -108,10 +108,12 @@ public class PositionItem {
public void setRangeMiles(double rangeMiles) { this.rangeMiles = rangeMiles; }
public static boolean equalTo(PositionItem positionItem1, PositionItem positionItem2) {
return positionItem1.getSrcCallsign().equals(positionItem2.getSrcCallsign()) &
positionItem1.getIsTransmit() == positionItem2.getIsTransmit() &&
Math.abs(positionItem1.getLongitude() - positionItem2.getLongitude()) <= MIN_COORDINATE_CHANGE_DELTA &
Math.abs(positionItem1.getLatitude() - positionItem2.getLatitude()) <= MIN_COORDINATE_CHANGE_DELTA;
@Override
public boolean equals(Object o) {
PositionItem positionItem = (PositionItem) o;
return getSrcCallsign().equals(positionItem.getSrcCallsign()) &
getIsTransmit() == positionItem.getIsTransmit() &&
Math.abs(getLongitude() - positionItem.getLongitude()) <= MIN_COORDINATE_CHANGE_DELTA &
Math.abs(getLatitude() - positionItem.getLatitude()) <= MIN_COORDINATE_CHANGE_DELTA;
}
}

Wyświetl plik

@ -24,7 +24,7 @@ public abstract class PositionItemDao {
@Transaction
public void upsertPositionItem(PositionItem positionItem) {
PositionItem oldPosition = getLastPositionItem(positionItem.getSrcCallsign());
if (oldPosition != null && PositionItem.equalTo(positionItem, oldPosition)) {
if (oldPosition != null && oldPosition.equals(positionItem)) {
// update id and coordinates from existing position
positionItem.setId(oldPosition.getId());
positionItem.setLatitude(oldPosition.getLatitude());

Wyświetl plik

@ -3,6 +3,8 @@ package com.radio.codec2talkie.storage.position;
import android.app.Application;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations;
import com.radio.codec2talkie.storage.AppDatabase;
@ -23,7 +25,7 @@ public class PositionItemRepository {
}
public LiveData<List<PositionItem>> getPositionItems(String srcCallsign) {
return _positionItemDao.getPositionItems(srcCallsign);
return Transformations.distinctUntilChanged(_positionItemDao.getPositionItems(srcCallsign));
}
public void deleteAllPositionItems() {

Wyświetl plik

@ -1,10 +1,14 @@
package com.radio.codec2talkie.storage.station;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.room.Entity;
import androidx.room.Index;
import androidx.room.PrimaryKey;
import java.util.Objects;
@Entity(indices = {@Index(value = {"srcCallsign"}, unique = true)})
public class StationItem {
@NonNull
@ -118,4 +122,15 @@ public class StationItem {
if (stationItem.getLogLine() != null)
setLogLine(stationItem.getLogLine());
}
@Override
public boolean equals(Object o) {
StationItem stationItem = (StationItem)o;
return srcCallsign.equals(stationItem.getSrcCallsign()) &&
timestampEpoch == stationItem.getTimestampEpoch() &&
Objects.equals(comment, stationItem.getComment()) &&
Objects.equals(dstCallsign, stationItem.getDstCallsign()) &&
latitude == stationItem.getLatitude() &&
longitude == stationItem.getLongitude();
}
}

Wyświetl plik

@ -5,6 +5,7 @@ import android.database.sqlite.SQLiteConstraintException;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations;
import com.radio.codec2talkie.storage.AppDatabase;
@ -19,7 +20,7 @@ public class StationItemRepository {
public StationItemRepository(Application application) {
AppDatabase appDatabase = AppDatabase.getDatabase(application);
_stationItemDao = appDatabase.stationitemDao();
_stationItems = _stationItemDao.getAllStationItems();
_stationItems = Transformations.distinctUntilChanged(_stationItemDao.getAllStationItems());
}
public LiveData<List<StationItem>> getAllStationItems() { return _stationItems; }