-
-
Notifications
You must be signed in to change notification settings - Fork 863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[android] Add Speed class #7955
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package app.organicmaps.util; | ||
|
||
import android.content.Context; | ||
import android.util.Pair; | ||
|
||
import java.text.DecimalFormat; | ||
import java.text.DecimalFormatSymbols; | ||
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("#.#"); | ||
|
||
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; | ||
} | ||
|
||
long start1 = System.nanoTime(); | ||
String formatString = (speedValue < 10.0)? "%.1f" : "%.0f"; | ||
String speedString = String.format(Locale.getDefault(), formatString, speedValue); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does caching the locale help to speed up the method? Are there other alternatives to String.format? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I've made some timing comparison with 2 other alternatives to You can find the code for this comparison in the function
These are the average times for each option:
Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:
This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:
I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about separating thousands? There are also Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized? |
||
long elapsed1 = System.nanoTime() - start1; | ||
|
||
Logger.i("LOCALE_MEASURE", "1) " + speedString); | ||
|
||
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); | ||
|
||
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); | ||
|
||
String text = String.format(Locale.US, | ||
"%5d / %5d / %5d", | ||
Math.round(0.001 * elapsed1), | ||
Math.round(0.001 * elapsed2), | ||
Math.round(0.001 * elapsed3)); | ||
|
||
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); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this string be pre-cached?