TrackStats { TrackStats(@NonNull List<MLocation> trackData) { if (!trackData.isEmpty()) { final TrackLabels labels = TrackLabels.from(trackData); if (labels != null) { exit = trackData.get(labels.exit); deploy = trackData.get(labels.deploy); land = trackData.get(labels.land); } final LatLngBounds.Builder boundsBuilder = LatLngBounds.builder(); for (MLocation loc : trackData) { altitude.expand(loc.altitude_gps); boundsBuilder.include(loc.latLng()); } bounds = boundsBuilder.build(); } else { bounds = null; } } TrackStats(@NonNull List<MLocation> trackData); boolean isDefined(); final Range altitude; public MLocation exit; public MLocation deploy; public MLocation land; @Nullable
    final LatLngBounds bounds; }
@Test public void trackStats() { final List<MLocation> points = new ArrayList<>(); points.add(point(0, FlightMode.MODE_GROUND)); points.add(point(1000, FlightMode.MODE_GROUND)); points.add(point(2000, FlightMode.MODE_WINGSUIT)); points.add(point(3000, FlightMode.MODE_WINGSUIT)); points.add(point(4000, FlightMode.MODE_WINGSUIT)); points.add(point(5000, FlightMode.MODE_CANOPY)); points.add(point(6000, FlightMode.MODE_CANOPY)); points.add(point(7000, FlightMode.MODE_GROUND)); final TrackStats stats = new TrackStats(points); assertEquals(2000, stats.exit.millis); assertEquals(4000, stats.deploy.millis); assertEquals(6000, stats.land.millis); assertEquals(100, stats.altitude.min, 0.01); assertEquals(1000, stats.altitude.max, 0.01); }