diff --git a/android/app/src/main/cpp/app/organicmaps/Framework.cpp b/android/app/src/main/cpp/app/organicmaps/Framework.cpp index d29a67a69e..fc3843aa35 100644 --- a/android/app/src/main/cpp/app/organicmaps/Framework.cpp +++ b/android/app/src/main/cpp/app/organicmaps/Framework.cpp @@ -1254,12 +1254,16 @@ Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) // String currentStreet, String nextStreet, String nextNextStreet, // double completionPercent, int vehicleTurnOrdinal, int // vehicleNextTurnOrdinal, int pedestrianTurnOrdinal, int exitNum, - // int totalTime, SingleLaneInfo[] lanes) + // int totalTime, SingleLaneInfo[] lanes, double speedLimitMps, + // boolean speedLimitExceeded, boolean shouldPlayWarningSignal, + // int nextStopPos, Distance distToNextStop, int timeToNextStop) + static jmethodID const ctorRouteInfoID = jni::GetConstructorID(env, klass, "(Lapp/organicmaps/util/Distance;Lapp/organicmaps/util/Distance;" "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DIIIII" - "[Lapp/organicmaps/routing/SingleLaneInfo;DZZ)V"); + "[Lapp/organicmaps/routing/SingleLaneInfo;DZZ" + "ILapp/organicmaps/util/Distance;I)V"); vector const & lanes = info.m_lanes; jobjectArray jLanes = nullptr; @@ -1289,13 +1293,15 @@ Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) auto const & rm = frm()->GetRoutingManager(); auto const isSpeedCamLimitExceeded = rm.IsRoutingActive() ? rm.IsSpeedCamLimitExceeded() : false; auto const shouldPlaySignal = frm()->GetRoutingManager().GetSpeedCamManager().ShouldPlayBeepSignal(); + jobject const result = env->NewObject( klass, ctorRouteInfoID, ToJavaDistance(env, info.m_distToTarget), ToJavaDistance(env, info.m_distToTurn), jni::ToJavaString(env, info.m_currentStreetName), jni::ToJavaString(env, info.m_nextStreetName), jni::ToJavaString(env, info.m_nextNextStreetName), info.m_completionPercent, info.m_turn, info.m_nextTurn, info.m_pedestrianTurn, info.m_exitNum, info.m_time, jLanes, info.m_speedLimitMps, static_cast(isSpeedCamLimitExceeded), - static_cast(shouldPlaySignal)); + static_cast(shouldPlaySignal), info.m_nextStopPos, + ToJavaDistance(env, info.m_distToNextStop), info.m_timeToNextStop); ASSERT(result, (jni::DescribeException())); return result; } 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 a789dd4c2f..a57564868b 100644 --- a/android/app/src/main/java/app/organicmaps/routing/NavigationController.java +++ b/android/app/src/main/java/app/organicmaps/routing/NavigationController.java @@ -1,6 +1,7 @@ package app.organicmaps.routing; import android.text.TextUtils; +import android.text.format.DateFormat; import android.view.View; import android.widget.ImageView; import android.widget.TextView; @@ -19,7 +20,10 @@ import app.organicmaps.util.Utils; import app.organicmaps.widget.menu.NavMenu; import com.google.android.material.bottomsheet.BottomSheetBehavior; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; +import java.util.concurrent.TimeUnit; public class NavigationController implements TrafficManager.TrafficCallback, NavMenu.NavMenuListener @@ -43,6 +47,12 @@ public class NavigationController implements TrafficManager.TrafficCallback, @NonNull private final LanesAdapter mLanesAdapter; + private final View mNextStopFrame; + private final TextView mNextStopPos; + private final TextView mNextStopDistance; + private final TextView mNextStopRemainingTime; + private final TextView mNextStopEta; + private final NavMenu mNavMenu; View.OnClickListener mOnSettingsClickListener; @@ -88,6 +98,12 @@ public class NavigationController implements TrafficManager.TrafficCallback, mLanesAdapter = new LanesAdapter(); initLanesRecycler(); + mNextStopFrame = topFrame.findViewById(R.id.next_stop_frame); + mNextStopPos = topFrame.findViewById(R.id.next_stop_pos); + mNextStopDistance = topFrame.findViewById(R.id.distance_to_next_stop); + mNextStopRemainingTime = topFrame.findViewById(R.id.remaining_time_to_next_stop); + mNextStopEta = topFrame.findViewById(R.id.eta_to_next_stop); + // Show a blank view below the navbar to hide the menu content final View navigationBarBackground = mFrame.findViewById(R.id.nav_bottom_sheet_nav_bar); final View nextTurnContainer = mFrame.findViewById(R.id.nav_next_turn_container); @@ -155,6 +171,9 @@ public class NavigationController implements TrafficManager.TrafficCallback, updateVehicle(info); updateStreetView(info); + + updateNextStopInfo(info); + mNavMenu.update(info); } @@ -168,6 +187,41 @@ public class NavigationController implements TrafficManager.TrafficCallback, mNextStreet.setText(info.nextStreet); } + private void updateNextStopInfo(@NonNull RoutingInfo info) + { + if ((info.nextStopPos > 0) && (info.nextStopPos < 100)) + { + // Show next stop info. + UiUtils.show(mNextStopFrame); + + mNextStopPos.setText(String.valueOf(info.nextStopPos)); + mNextStopDistance.setText(info.distToNextStop.mDistanceStr + " " + + info.distToNextStop.getUnitsStr(mFrame.getContext())); + + // Display remaining time to next stop. + final long hours = TimeUnit.SECONDS.toHours(info.timeToNextStop); + final long minutes = TimeUnit.SECONDS.toMinutes(info.timeToNextStop) % 60; + + String timeString = ""; + + if (hours > 0) + timeString += String.valueOf(hours) + " " + mFrame.getResources().getString(R.string.hour); + + timeString += String.valueOf(minutes) + " " + mFrame.getResources().getString(R.string.minute); + mNextStopRemainingTime.setText(timeString); + + // ETA to next stop. + final String format = DateFormat.is24HourFormat(mFrame.getContext()) ? "HH:mm" : "h:mm a"; + final LocalTime localTime = LocalTime.now().plusSeconds(info.timeToNextStop); + mNextStopEta.setText(localTime.format(DateTimeFormatter.ofPattern(format))); + } + else + { + // Hide next stop info. + UiUtils.hide(mNextStopFrame); + } + } + public void show(boolean show) { if (show && !UiUtils.isVisible(mFrame)) diff --git a/android/app/src/main/java/app/organicmaps/routing/RoutingInfo.java b/android/app/src/main/java/app/organicmaps/routing/RoutingInfo.java index 6b0a393783..dbdf6c1324 100644 --- a/android/app/src/main/java/app/organicmaps/routing/RoutingInfo.java +++ b/android/app/src/main/java/app/organicmaps/routing/RoutingInfo.java @@ -39,6 +39,10 @@ public class RoutingInfo public final double speedLimitMps; private final boolean speedCamLimitExceeded; private final boolean shouldPlayWarningSignal; + // Next stop info. + public final int nextStopPos; + public final Distance distToNextStop; + public final int timeToNextStop; /** * IMPORTANT : Order of enum values MUST BE the same as native CarDirection enum. @@ -144,7 +148,7 @@ public class RoutingInfo public RoutingInfo(Distance distToTarget, Distance distToTurn, String currentStreet, String nextStreet, String nextNextStreet, double completionPercent, int vehicleTurnOrdinal, int vehicleNextTurnOrdinal, int pedestrianTurnOrdinal, int exitNum, int totalTime, SingleLaneInfo[] lanes, double speedLimitMps, boolean speedLimitExceeded, - boolean shouldPlayWarningSignal) + boolean shouldPlayWarningSignal, int nextStopPos, Distance distToNextStop, int timeToNextStop) { this.distToTarget = distToTarget; this.distToTurn = distToTurn; @@ -161,6 +165,9 @@ public class RoutingInfo this.speedLimitMps = speedLimitMps; this.speedCamLimitExceeded = speedLimitExceeded; this.shouldPlayWarningSignal = shouldPlayWarningSignal; + this.nextStopPos = nextStopPos; + this.distToNextStop = distToNextStop; + this.timeToNextStop = timeToNextStop; } public boolean isSpeedCamLimitExceeded() diff --git a/android/app/src/main/res/drawable/ic_route_stop.xml b/android/app/src/main/res/drawable/ic_route_stop.xml new file mode 100644 index 0000000000..2159ac82ea --- /dev/null +++ b/android/app/src/main/res/drawable/ic_route_stop.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout-land/layout_nav_top.xml b/android/app/src/main/res/layout-land/layout_nav_top.xml index 681ec9c838..8d000bba9d 100644 --- a/android/app/src/main/res/layout-land/layout_nav_top.xml +++ b/android/app/src/main/res/layout-land/layout_nav_top.xml @@ -122,4 +122,86 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/layout_nav_top.xml b/android/app/src/main/res/layout/layout_nav_top.xml index 8483c74286..4f8fdfc085 100644 --- a/android/app/src/main/res/layout/layout_nav_top.xml +++ b/android/app/src/main/res/layout/layout_nav_top.xml @@ -122,4 +122,86 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/values/styles-text.xml b/android/app/src/main/res/values/styles-text.xml index ba8d84baeb..2b6e666866 100644 --- a/android/app/src/main/res/values/styles-text.xml +++ b/android/app/src/main/res/values/styles-text.xml @@ -150,6 +150,11 @@ ?android:textColorSecondary + +