[android] Add Speed class
Signed-off-by: Gonzalo Pesquero <gpesquero@yahoo.es>
This commit is contained in:
parent
5a8ccd9115
commit
2bb8b7aa50
7 changed files with 236 additions and 4 deletions
|
@ -1953,4 +1953,10 @@ Java_app_organicmaps_Framework_nativeGetKayakHotelLink(JNIEnv * env, jclass, jst
|
|||
return url.empty() ? nullptr : jni::ToJavaString(env, url);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_app_organicmaps_Framework_nativeGetUnits(JNIEnv *, jclass)
|
||||
{
|
||||
return static_cast<jint>(measurement_utils::GetMeasurementUnits());
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
@ -57,6 +57,14 @@ JNIEXPORT jobject JNICALL Java_app_organicmaps_util_StringUtils_nativeFormatSpee
|
|||
platform::GetLocalizedSpeedUnits(units));
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_app_organicmaps_util_StringUtils_nativeStringFormatSpeedAndUnits(
|
||||
JNIEnv * env, jclass thiz, jdouble metersPerSecond)
|
||||
{
|
||||
auto const units = measurement_utils::GetMeasurementUnits();
|
||||
return jni::ToJavaString(env, measurement_utils::FormatSpeedNumeric(metersPerSecond, units) +
|
||||
";" + platform::GetLocalizedSpeedUnits(units));
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_app_organicmaps_util_StringUtils_nativeFormatDistance(JNIEnv * env, jclass, jdouble distanceInMeters)
|
||||
{
|
||||
|
|
|
@ -60,6 +60,10 @@ public class Framework
|
|||
public static final int ROUTER_TYPE_TRANSIT = 3;
|
||||
public static final int ROUTER_TYPE_RULER = 4;
|
||||
|
||||
// Units values shall be the same as the ones defined in c++ in <platform/measurement_utils.hpp>.
|
||||
public static final int UNITS_METRIC = 0;
|
||||
public static final int UNITS_IMPERIAL = 1;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({ROUTE_REBUILD_AFTER_POINTS_LOADING})
|
||||
public @interface RouteRecommendationType {}
|
||||
|
@ -460,4 +464,6 @@ public class Framework
|
|||
@Nullable
|
||||
public static native String nativeGetKayakHotelLink(@NonNull String countryIsoCode, @NonNull String uri,
|
||||
long firstDaySec, long lastDaySec, boolean isReferral);
|
||||
|
||||
public static native int nativeGetUnits();
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ public class NavigationController implements TrafficManager.TrafficCallback,
|
|||
updateVehicle(info);
|
||||
|
||||
updateStreetView(info);
|
||||
mNavMenu.update(info);
|
||||
mNavMenu.update(info, Framework.nativeGetUnits());
|
||||
}
|
||||
|
||||
private void updateStreetView(@NonNull RoutingInfo info)
|
||||
|
|
171
android/app/src/main/java/app/organicmaps/util/Speed.java
Normal file
171
android/app/src/main/java/app/organicmaps/util/Speed.java
Normal file
|
@ -0,0 +1,171 @@
|
|||
package app.organicmaps.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
|
||||
import app.organicmaps.Framework;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
public class Speed
|
||||
{
|
||||
private static String mUnitStringKmh = "km/h";
|
||||
private static String mUnitStringMiph = "mph";
|
||||
|
||||
private static char mDecimalSeparator = Character.MIN_VALUE;
|
||||
|
||||
public static double MpsToKmph(double mps) { return mps * 3.6; }
|
||||
public static double MpsToMiph(double mps) { return mps * 2.236936; }
|
||||
|
||||
public static void setUnitStringKmh(String unitStringKmh) { mUnitStringKmh = unitStringKmh; }
|
||||
public static void setUnitStringMiph(String unitStringMiph) { mUnitStringMiph = unitStringMiph; }
|
||||
|
||||
private final static DecimalFormat mDecimalFormatNoDecimal = new DecimalFormat("#");
|
||||
private final static DecimalFormat mDecimalFormatOneDecimal = new DecimalFormat("0.0");
|
||||
|
||||
private final static Locale mLocale = Locale.getDefault();
|
||||
|
||||
private final static StringBuilder mSb = new StringBuilder();
|
||||
private final static Formatter mFormatter = new Formatter(mSb, mLocale);
|
||||
|
||||
private final static NumberFormat mNumberFormatNoDecimal = NumberFormat.getInstance(mLocale);
|
||||
private final static NumberFormat mNumberFormatOneDecimal = NumberFormat.getInstance(mLocale);
|
||||
|
||||
public static Pair<String, String> formatMeasurements(double speedInMetersPerSecond, int units,
|
||||
Context context)
|
||||
{
|
||||
double speedValue;
|
||||
String unitsString;
|
||||
|
||||
if (units == Framework.UNITS_IMPERIAL)
|
||||
{
|
||||
speedValue = MpsToMiph(speedInMetersPerSecond);
|
||||
unitsString = mUnitStringMiph;
|
||||
}
|
||||
else
|
||||
{
|
||||
speedValue = MpsToKmph(speedInMetersPerSecond);
|
||||
unitsString = mUnitStringKmh;
|
||||
}
|
||||
|
||||
// Option 1: String.format()
|
||||
long start1 = System.nanoTime();
|
||||
String formatString = (speedValue < 10.0)? "%.1f" : "%.0f";
|
||||
String speedString = String.format(mLocale, formatString, speedValue);
|
||||
long elapsed1 = System.nanoTime() - start1;
|
||||
Logger.i("LOCALE_MEASURE", "1) " + speedString);
|
||||
|
||||
// Option 2: DecimalFormat class
|
||||
long start2 = System.nanoTime();
|
||||
if (speedValue < 10.0)
|
||||
speedString = mDecimalFormatOneDecimal.format(speedValue);
|
||||
else
|
||||
speedString = mDecimalFormatNoDecimal.format(speedValue);
|
||||
long elapsed2 = System.nanoTime() - start2;
|
||||
Logger.i("LOCALE_MEASURE", "2) " + speedString);
|
||||
|
||||
// Option 3: Long.toString() + StringBuffer.insert()
|
||||
long start3 = System.nanoTime();
|
||||
if (speedValue < 10.0)
|
||||
{
|
||||
speedString = Long.toString(Math.round(speedValue * 10.0));
|
||||
|
||||
StringBuffer buffer = new StringBuffer(speedString);
|
||||
|
||||
if (mDecimalSeparator == Character.MIN_VALUE)
|
||||
mDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
|
||||
|
||||
// For low values (< 1.0), force to have 2 characters in string.
|
||||
if (buffer.length() < 2)
|
||||
buffer.insert(0, "0");
|
||||
|
||||
buffer.insert(1, mDecimalSeparator);
|
||||
|
||||
speedString = buffer.toString();
|
||||
}
|
||||
else
|
||||
speedString = Long.toString(Math.round(speedValue));
|
||||
long elapsed3 = System.nanoTime() - start3;
|
||||
Logger.i("LOCALE_MEASURE", "3) " + speedString);
|
||||
|
||||
// Option 4: Formatter class
|
||||
mSb.setLength(0);
|
||||
long start4 = System.nanoTime();
|
||||
if (speedValue < 10.0)
|
||||
mFormatter.format("%.1f", speedValue);
|
||||
else
|
||||
mFormatter.format("%d", Math.round(speedValue));
|
||||
speedString = mSb.toString();
|
||||
long elapsed4 = System.nanoTime() - start4;
|
||||
Logger.i("LOCALE_MEASURE", "4) " + speedString);
|
||||
|
||||
// Option 5: NumberFormat class
|
||||
mNumberFormatNoDecimal.setMaximumFractionDigits(0);
|
||||
mNumberFormatOneDecimal.setMaximumFractionDigits(1);
|
||||
long start5 = System.nanoTime();
|
||||
if (speedValue < 10.0)
|
||||
speedString = mNumberFormatOneDecimal.format(speedValue);
|
||||
else
|
||||
speedString = mNumberFormatNoDecimal.format(Math.round(speedValue));
|
||||
long elapsed5 = System.nanoTime() - start5;
|
||||
Logger.i("LOCALE_MEASURE", "5) " + speedString);
|
||||
|
||||
String text = String.format(Locale.US,
|
||||
"Java calls: %5d / %5d / %5d / %5d / %5d",
|
||||
Math.round(0.001 * elapsed1),
|
||||
Math.round(0.001 * elapsed2),
|
||||
Math.round(0.001 * elapsed3),
|
||||
Math.round(0.001 * elapsed4),
|
||||
Math.round(0.001 * elapsed5));
|
||||
Logger.i("LOCALE_MEASURE", text);
|
||||
|
||||
return new Pair<>(speedString, unitsString);
|
||||
}
|
||||
|
||||
public static Pair<String, String> format(double speedInMetersPerSecond, int units,
|
||||
Context context)
|
||||
{
|
||||
double speedValue;
|
||||
String unitsString;
|
||||
|
||||
if (units == Framework.UNITS_IMPERIAL)
|
||||
{
|
||||
speedValue = MpsToMiph(speedInMetersPerSecond);
|
||||
unitsString = mUnitStringMiph;
|
||||
}
|
||||
else
|
||||
{
|
||||
speedValue = MpsToKmph(speedInMetersPerSecond);
|
||||
unitsString = mUnitStringKmh;
|
||||
}
|
||||
|
||||
String speedString;
|
||||
|
||||
if (speedValue < 10.0)
|
||||
{
|
||||
speedString = Long.toString(Math.round(speedValue * 10.0));
|
||||
|
||||
StringBuffer buffer = new StringBuffer(speedString);
|
||||
|
||||
if (mDecimalSeparator == Character.MIN_VALUE)
|
||||
mDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
|
||||
|
||||
// For low values (< 1.0), force to have 2 characters in string.
|
||||
if (buffer.length() < 2)
|
||||
buffer.insert(0, "0");
|
||||
|
||||
buffer.insert(1, mDecimalSeparator);
|
||||
|
||||
speedString = buffer.toString();
|
||||
}
|
||||
else
|
||||
speedString = Long.toString(Math.round(speedValue));
|
||||
|
||||
return new Pair<>(speedString, unitsString);
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ public class StringUtils
|
|||
public static native String[] nativeFilterContainsNormalized(String[] strings, String substr);
|
||||
|
||||
public static native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
|
||||
public static native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
|
||||
public static native Distance nativeFormatDistance(double meters);
|
||||
@NonNull
|
||||
public static native Pair<String, String> nativeGetLocalizedDistanceUnits();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package app.organicmaps.widget.menu;
|
||||
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
@ -15,12 +16,16 @@ import app.organicmaps.location.LocationHelper;
|
|||
import app.organicmaps.routing.RoutingInfo;
|
||||
import app.organicmaps.sound.TtsPlayer;
|
||||
import app.organicmaps.util.Graphics;
|
||||
import app.organicmaps.util.Speed;
|
||||
import app.organicmaps.util.StringUtils;
|
||||
import app.organicmaps.util.UiUtils;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class NavMenu
|
||||
|
@ -203,22 +208,57 @@ public class NavMenu
|
|||
mTimeEstimate.setText(localTime.format(DateTimeFormatter.ofPattern(format)));
|
||||
}
|
||||
|
||||
private void updateSpeedView(@NonNull RoutingInfo info)
|
||||
private void updateSpeedView(@NonNull RoutingInfo info, int units)
|
||||
{
|
||||
final Location last = LocationHelper.from(mActivity).getSavedLocation();
|
||||
if (last == null)
|
||||
return;
|
||||
|
||||
// Log measurements for different Java implementations.
|
||||
Speed.formatMeasurements(last.getSpeed(), units, mActivity.getApplicationContext());
|
||||
|
||||
// Speed formatting using native calls.
|
||||
long start1 = System.nanoTime();
|
||||
Pair<String, String> speedAndUnits = StringUtils.nativeFormatSpeedAndUnits(last.getSpeed());
|
||||
long elapsed1 = System.nanoTime() - start1;
|
||||
|
||||
mSpeedUnits.setText(speedAndUnits.second);
|
||||
mSpeedValue.setText(speedAndUnits.first);
|
||||
|
||||
// Speed formatting using native calls. Speed and units is returned in a single string.
|
||||
long start2 = System.nanoTime();
|
||||
String speedAndUnitsString = StringUtils.nativeStringFormatSpeedAndUnits(last.getSpeed());
|
||||
// Speed and units are separated by semicolon ";" in returned string.
|
||||
int separatorPos = speedAndUnitsString.indexOf(";");
|
||||
String speedString = speedAndUnitsString.substring(0, separatorPos);
|
||||
String unitsString = speedAndUnitsString.substring(separatorPos + 1);
|
||||
long elapsed2 = System.nanoTime() - start2;
|
||||
|
||||
mSpeedUnits.setText(speedString);
|
||||
mSpeedValue.setText(unitsString);
|
||||
|
||||
// Speed formatting using Android Java calls.
|
||||
long start3 = System.nanoTime();
|
||||
speedAndUnits = Speed.format(last.getSpeed(), units, mActivity.getApplicationContext());
|
||||
long elapsed3 = System.nanoTime() - start3;
|
||||
|
||||
mSpeedUnits.setText(speedAndUnits.second);
|
||||
mSpeedValue.setText(speedAndUnits.first);
|
||||
|
||||
String text = String.format(Locale.US,
|
||||
"Native calls: %5d / %5d / %5d",
|
||||
Math.round(0.001 * elapsed1),
|
||||
Math.round(0.001 * elapsed2),
|
||||
Math.round(0.001 * elapsed3));
|
||||
|
||||
Logger.i("LOCALE_MEASURE", text);
|
||||
|
||||
mSpeedViewContainer.setActivated(info.isSpeedLimitExceeded());
|
||||
}
|
||||
|
||||
public void update(@NonNull RoutingInfo info)
|
||||
public void update(@NonNull RoutingInfo info, int units)
|
||||
{
|
||||
updateSpeedView(info);
|
||||
updateSpeedView(info, units);
|
||||
updateTime(info.totalTimeInSeconds);
|
||||
mDistanceValue.setText(info.distToTarget.mDistanceStr);
|
||||
mDistanceUnits.setText(info.distToTarget.getUnitsStr(mActivity.getApplicationContext()));
|
||||
|
|
Reference in a new issue