From f960b3959f9cf40313393c25de01551565de993a Mon Sep 17 00:00:00 2001 From: David Gekeler Date: Fri, 6 Jun 2025 17:54:13 +0200 Subject: [PATCH] [android] Add average speed calculation and change speed view to display it Signed-off-by: David Gekeler --- .../routing/NavigationController.java | 9 ++-- .../sdk/location/LocationHelper.java | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/app/organicmaps/routing/NavigationController.java b/android/app/src/main/java/app/organicmaps/routing/NavigationController.java index 7ca7e557f..82a782869 100644 --- a/android/app/src/main/java/app/organicmaps/routing/NavigationController.java +++ b/android/app/src/main/java/app/organicmaps/routing/NavigationController.java @@ -18,6 +18,7 @@ import app.organicmaps.R; import app.organicmaps.maplayer.MapButtonsViewModel; import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Router; +import app.organicmaps.sdk.location.LocationHelper; import app.organicmaps.sdk.maplayer.traffic.TrafficManager; import app.organicmaps.sdk.routing.CarDirection; import app.organicmaps.sdk.routing.RoutingController; @@ -267,16 +268,18 @@ public class NavigationController implements TrafficManager.TrafficCallback, Nav private void updateSpeedWidgets(@NonNull final RoutingInfo info) { - final Location location = MwmApplication.from(mFrame.getContext()).getLocationHelper().getSavedLocation(); + final LocationHelper locationHelper = MwmApplication.from(mFrame.getContext()).getLocationHelper(); + final Location location = locationHelper.getSavedLocation(); if (location == null) { mSpeedLimit.setSpeedLimit(-1, false); mCurrentSpeed.setCurrentSpeed(-1); return; } + final double currentAvgSpeed = locationHelper.getAverageSpeed(); final int fSpeedLimit = StringUtils.nativeFormatSpeed(info.speedLimitMps); - final boolean speedLimitExceeded = fSpeedLimit < StringUtils.nativeFormatSpeed(location.getSpeed()); + final boolean speedLimitExceeded = fSpeedLimit < StringUtils.nativeFormatSpeed(currentAvgSpeed); mSpeedLimit.setSpeedLimit(fSpeedLimit, speedLimitExceeded); - mCurrentSpeed.setCurrentSpeed(location.getSpeed()); + mCurrentSpeed.setCurrentSpeed(currentAvgSpeed); } } diff --git a/android/sdk/src/main/java/app/organicmaps/sdk/location/LocationHelper.java b/android/sdk/src/main/java/app/organicmaps/sdk/location/LocationHelper.java index 21ca52cc6..9ddcde5f3 100644 --- a/android/sdk/src/main/java/app/organicmaps/sdk/location/LocationHelper.java +++ b/android/sdk/src/main/java/app/organicmaps/sdk/location/LocationHelper.java @@ -26,6 +26,7 @@ import app.organicmaps.sdk.util.LocationUtils; import app.organicmaps.sdk.util.NetworkPolicy; import app.organicmaps.sdk.util.log.Logger; import org.chromium.base.ObserverList; +import java.util.ArrayList; public class LocationHelper implements BaseLocationProvider.Listener { @@ -35,6 +36,8 @@ public class LocationHelper implements BaseLocationProvider.Listener private static final long AGPS_EXPIRATION_TIME_MS = 16 * 60 * 60 * 1000; // 16 hours private static final long LOCATION_UPDATE_TIMEOUT_MS = 30 * 1000; // 30 seconds + private static final double SPEED_AVERAGING_TIME = 0.5; // 0.5 seconds + @NonNull private final Context mContext; @NonNull @@ -56,6 +59,10 @@ public class LocationHelper implements BaseLocationProvider.Listener private Handler mHandler; private Runnable mLocationTimeoutRunnable = this::notifyLocationUpdateTimeout; + private double mTimeElapsedAtLastAverage = Double.NaN; + private float mLastAverageSpeed = Float.NaN; + private ArrayList mSpeedHistory = new ArrayList<>(); + @NonNull private final GnssStatusCompat.Callback mGnssStatusCallback = new GnssStatusCompat.Callback() { @Override @@ -167,6 +174,8 @@ public class LocationHelper implements BaseLocationProvider.Listener mSavedLocation.getLongitude(), mSavedLocation.getAccuracy(), mSavedLocation.getAltitude(), mSavedLocation.getSpeed(), mSavedLocation.getBearing()); + + updateSpeedHistory(); } private void notifyLocationUpdateTimeout() @@ -479,4 +488,49 @@ public class LocationHelper implements BaseLocationProvider.Listener Framework.nativeRunFirstLaunchAnimation(); } } + + private void updateSpeedHistory() + { + if (mSavedLocation == null) + { + return; + } + + if (Double.isNaN(mTimeElapsedAtLastAverage)) + { + mTimeElapsedAtLastAverage = mSavedLocation.getElapsedRealtimeNanos() * 1.0E-9; + } + mSpeedHistory.add(mSavedLocation.getSpeed()); + } + + public float getAverageSpeed() + { + if (mSavedLocation == null) + { + return Float.NaN; + } + if (Double.isNaN(mTimeElapsedAtLastAverage)) + { + updateSpeedHistory(); + } + if (mSavedLocation.getElapsedRealtimeNanos() * 1.0E-9 - mTimeElapsedAtLastAverage < SPEED_AVERAGING_TIME) + { + if (!Float.isNaN(mLastAverageSpeed)) + { + return mLastAverageSpeed; + } + else + { + return mSavedLocation.getSpeed(); + } + } + else + { + mLastAverageSpeed = mSpeedHistory.stream().reduce(0.0F, Float::sum); + mLastAverageSpeed /= mSpeedHistory.size(); + mSpeedHistory.clear(); + mTimeElapsedAtLastAverage = mSavedLocation.getElapsedRealtimeNanos() * 1.0E-9; + return mLastAverageSpeed; + } + } }