App 2.39.0, server 2.7.0: Grid with map
A new Overview style: the Grid over the roads round the car from
OpenStreetMap, drawn in the floor's perspective, heading up, the bigger
roads glowing brighter, the car as a chevron.
Server: POST /v1/map/roads {z:14,x,y} fetches a tile's drivable roads
from Overpass (OVERPASS_URL; one request at a time, at least a second
apart), simplifies them to tile-local points in four classes, caches
them for 30 days and never logs the tile.
App: MapRoads keeps the 3x3 tiles round the car from its own cache or
the server; GPS only while the style is shown; bearing from the GPS or
from successive positions. Without GPS, server or roads the plain floor
says why. OSM attribution on screen and in LICENSE.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
@@ -70,6 +70,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
private TerminalView terminalView;
|
||||
private GridView gridView;
|
||||
private VisorView visorView;
|
||||
/** "Grid with map": the same style over the roads round the car (MapRoads, fed by GPS here). */
|
||||
private GridView gridMapView;
|
||||
private MapRoads mapRoads;
|
||||
private android.location.LocationListener mapListener;
|
||||
private boolean inFront;
|
||||
/** The pane of each Overview style, by its {@link OverviewStyle} ordinal. */
|
||||
private View[] stylePanes;
|
||||
private View consumptionPane;
|
||||
@@ -345,9 +350,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
mgPane = drawnPane(octagonView);
|
||||
terminalView = new TerminalView(this);
|
||||
gridView = new GridView(this);
|
||||
mapRoads = new MapRoads(this);
|
||||
gridMapView = new GridView(this, mapRoads);
|
||||
visorView = new VisorView(this);
|
||||
java.util.Collections.addAll(canvasStyles, new MinimalView(this), terminalView,
|
||||
new NixieView(this), new ChronographView(this), gridView, new TimeCircuitsView(this),
|
||||
new NixieView(this), new ChronographView(this), gridView, gridMapView, new TimeCircuitsView(this),
|
||||
new QuestView(this), visorView, new EmpireView(this));
|
||||
View[] canvasPanes = new View[canvasStyles.size()];
|
||||
for (int i = 0; i < canvasPanes.length; i++) canvasPanes[i] = drawnPane(canvasStyles.get(i));
|
||||
@@ -487,6 +494,8 @@ public class MainActivity extends AppCompatActivity {
|
||||
// Poll state and log only while the screen is up; onPause cancels it.
|
||||
uiHandler.post(uiRefresh);
|
||||
uiHandler.post(overviewRefresh);
|
||||
inFront = true;
|
||||
updateMapLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -534,6 +543,8 @@ public class MainActivity extends AppCompatActivity {
|
||||
// Stop polling off-screen: this activity has no reason to spend cycles then.
|
||||
uiHandler.removeCallbacks(uiRefresh);
|
||||
uiHandler.removeCallbacks(overviewRefresh);
|
||||
inFront = false;
|
||||
updateMapLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1725,9 +1736,56 @@ public class MainActivity extends AppCompatActivity {
|
||||
retroView.setAccentPalette(!originalColours(OverviewStyle.RETRO));
|
||||
terminalView.setAccentPalette(!originalColours(OverviewStyle.TERMINAL));
|
||||
gridView.setAccentPalette(!originalColours(OverviewStyle.GRID));
|
||||
gridMapView.setAccentPalette(!originalColours(OverviewStyle.GRID_MAP));
|
||||
visorView.setAccentPalette(!originalColours(OverviewStyle.VISOR));
|
||||
// The accent choices depend on the style ("Original colours" for Retro and Terminal).
|
||||
if (settingsPane != null) bindAccentColor();
|
||||
updateMapLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* GPS for the Grid's map, only while "Grid with map" is the style and the app is in front;
|
||||
* every fix goes to {@link MapRoads}. Without the location permission there is no map (the
|
||||
* floor says it waits for GPS), never a crash.
|
||||
*/
|
||||
private void updateMapLocation() {
|
||||
android.location.LocationManager lm =
|
||||
(android.location.LocationManager) getSystemService(LOCATION_SERVICE);
|
||||
if (lm == null || mapRoads == null) return;
|
||||
boolean wanted = inFront && overviewStyle() == OverviewStyle.GRID_MAP;
|
||||
if (!wanted) {
|
||||
if (mapListener != null) {
|
||||
try {
|
||||
lm.removeUpdates(mapListener);
|
||||
} catch (RuntimeException ignored) {
|
||||
// already gone
|
||||
}
|
||||
mapListener = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mapListener != null) return;
|
||||
if (checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
!= android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
android.location.LocationListener listener = new android.location.LocationListener() {
|
||||
@Override public void onLocationChanged(android.location.Location location) { mapRoads.onFix(location); }
|
||||
@Override public void onStatusChanged(String provider, int status, android.os.Bundle extras) { }
|
||||
@Override public void onProviderEnabled(String provider) { }
|
||||
@Override public void onProviderDisabled(String provider) { }
|
||||
};
|
||||
try {
|
||||
lm.requestLocationUpdates(android.location.LocationManager.GPS_PROVIDER, 1000L, 0f, listener);
|
||||
mapListener = listener;
|
||||
android.location.Location last = lm.getLastKnownLocation(android.location.LocationManager.GPS_PROVIDER);
|
||||
if (last != null && android.os.SystemClock.elapsedRealtimeNanos() - last.getElapsedRealtimeNanos()
|
||||
< MapRoads.FIX_FRESH_MS * 1_000_000L) {
|
||||
mapRoads.onFix(last);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
android.util.Log.w("MainActivity", "No GPS for the map: " + e.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1757,6 +1815,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
getString(R.string.overview_style_minimal), getString(R.string.overview_style_terminal),
|
||||
getString(R.string.overview_style_nixie),
|
||||
getString(R.string.overview_style_chronograph), getString(R.string.overview_style_grid),
|
||||
getString(R.string.overview_style_grid_map),
|
||||
getString(R.string.overview_style_time_circuits), getString(R.string.overview_style_quest),
|
||||
getString(R.string.overview_style_visor), getString(R.string.overview_style_empire) };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user