Cleanup: mainly code formatting and made LocationIterator implement autoclosable.

This commit is contained in:
Dennis Guse
2019-09-07 12:23:56 +02:00
parent 025dee6821
commit 87d92d25f9
104 changed files with 1076 additions and 1526 deletions
@@ -34,13 +34,13 @@ public class FileUtils {
/**
* Used to transfer picture from the camera.
*/
public static final String FILEPROVIDER = BuildConfig.APPLICATION_ID + ".fileprovider";
static final String FILEPROVIDER = BuildConfig.APPLICATION_ID + ".fileprovider";
/**
* Our external storage directory.
*/
static final String SDCARD_TOP_DIR = "OpenTracks";
static final String TRACK_PREFIX = "OpenTracks";
private static final String TRACK_PREFIX = "OpenTracks";
/**
* The maximum FAT32 path length. See the FAT32 spec at
* http://msdn.microsoft.com/en-us/windows/hardware/gg463080
@@ -127,16 +127,14 @@ public class FileUtils {
}
/**
* Builds a filename with the given base name (prefix) and the given
* extension, possibly adding a suffix to ensure the file doesn't exist.
* Builds a filename with the given base name (prefix) and the given extension, possibly adding a suffix to ensure the file doesn't exist.
*
* @param directory the directory the file will live in
* @param fileBaseName the prefix for the file name
* @param extension the file's extension
* @return the complete file name, without the directory
*/
public static synchronized String buildUniqueFileName(
File directory, String fileBaseName, String extension) {
public static synchronized String buildUniqueFileName(File directory, String fileBaseName, String extension) {
return buildUniqueFileName(directory, fileBaseName, extension, 0);
}
@@ -154,7 +152,8 @@ public class FileUtils {
}
/**
* Gets the extension from a file name. Returns null if there is no extension.
* Gets the extension from a file name.
* Returns null if there is no extension.
*
* @param fileName the file name
*/
@@ -173,8 +172,7 @@ public class FileUtils {
}
/**
* Builds a filename with the given base and the given extension, possibly
* adding a suffix to ensure the file doesn't exist.
* Builds a filename with the given base and the given extension, possibly adding a suffix to ensure the file doesn't exist.
*
* @param directory the directory the filename will be located in
* @param base the base for the filename
@@ -182,8 +180,7 @@ public class FileUtils {
* @param suffix the first numeric suffix to try to use, or 0 for none
* @return the complete filename, without the directory
*/
private static String buildUniqueFileName(
File directory, String base, String extension, int suffix) {
private static String buildUniqueFileName(File directory, String base, String extension, int suffix) {
String suffixName = "";
if (suffix > 0) {
suffixName += "(" + suffix + ")";
@@ -201,10 +198,9 @@ public class FileUtils {
}
/**
* Sanitizes the name as a valid fat32 filename. For simplicity, fat32
* filename characters may be any combination of letters, digits, or
* characters with code point values greater than 127. Replaces the invalid
* characters with "_" and collapses multiple "_" together.
* Sanitizes the name as a valid fat32 filename.
* For simplicity, fat32 filename characters may be any combination of letters, digits, or characters with code point values greater than 127.
* Replaces the invalid characters with "_" and collapses multiple "_" together.
*
* @param name name
*/
@@ -260,8 +256,7 @@ public class FileUtils {
}
/**
* Truncates the name if necessary so the filename path length (directory +
* name + suffix) meets the Fat32 path limit.
* Truncates the name if necessary so the filename path length (directory + name + suffix) meets the Fat32 path limit.
*
* @param directory directory
* @param name name
@@ -273,8 +268,8 @@ public class FileUtils {
if (name.length() + requiredLength > MAX_FAT32_PATH_LENGTH) {
int limit = MAX_FAT32_PATH_LENGTH - requiredLength;
return name.substring(0, limit);
} else {
return name;
}
return name;
}
}
@@ -48,12 +48,13 @@ public class IntentUtils {
private final static String TAG = IntentUtils.class.getSimpleName();
private static final String JPEG_EXTENSION = "jpeg";
private IntentUtils() {
}
/**
* Creates an intent with {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} and
* {@link Intent#FLAG_ACTIVITY_NEW_TASK}.
* Creates an intent with {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} and {@link Intent#FLAG_ACTIVITY_NEW_TASK}.
*
* @param context the context
* @param cls the class
@@ -62,12 +63,10 @@ public class IntentUtils {
return new Intent(context, cls).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
}
private static final String JPEG_EXTENSION = "jpeg";
/**
* Creates an intent to share a track file with an app.
*
* @param context the context
* @param context the context
* @param trackIds the track ids
*/
public static Intent newShareFileIntent(Context context, long[] trackIds) {
@@ -90,6 +89,14 @@ public class IntentUtils {
showCoordinateOnMap(context, waypoint.getLocation().getLatitude(), waypoint.getLocation().getLongitude(), waypoint.getName());
}
/**
* Send intent to show coordinates on a map (needs an another app).
*
* @param context the context
* @param latitude the latitude
* @param longitude the longitude
* @param label the label
*/
public static void showCoordinateOnMap(Context context, double latitude, double longitude, String label) {
//SEE https://developer.android.com/guide/components/intents-common.html#Maps
String uri = "geo:0,0?q=" + latitude + "," + longitude;
@@ -61,11 +61,7 @@ public class ListItemUtils {
* @param description the description value
* @param photoUrl the photo url
*/
public static void setListItem(Activity activity, View view, boolean isRecording,
boolean isPaused, int iconId, int iconContentDescriptionId, String name,
String totalTime, String totalDistance, int markerCount, long startTime,
boolean useRelativeTime, String category, String description, String photoUrl) {
public static void setListItem(Activity activity, View view, boolean isRecording, boolean isPaused, int iconId, int iconContentDescriptionId, String name, String totalTime, String totalDistance, int markerCount, long startTime, boolean useRelativeTime, String category, String description, String photoUrl) {
// Set photo
ImageView photo = view.findViewById(R.id.list_item_photo);
ImageView textGradient = view.findViewById(R.id.list_item_text_gradient);
@@ -134,17 +130,11 @@ public class ListItemUtils {
setTextView(activity, timeTextView, dateTime[1], hasPhoto);
// Set category and description
TextView categoryDescriptionTextView = view.findViewById(
R.id.list_item_category_description);
String categoryDescription = isRecording ? null
: StringUtils.getCategoryDescription(category, description);
TextView categoryDescriptionTextView = view.findViewById(R.id.list_item_category_description);
String categoryDescription = isRecording ? null : StringUtils.getCategoryDescription(category, description);
/*
* Place categoryDescription in either ownerTimeDistanceTextView or
* categoryDescriptionTextView
*/
if (timeDistanceTextView.getVisibility() == View.GONE
&& markerCountIcon.getVisibility() == View.GONE) {
// Place categoryDescription in either ownerTimeDistanceTextView or categoryDescriptionTextView
if (timeDistanceTextView.getVisibility() == View.GONE && markerCountIcon.getVisibility() == View.GONE) {
setTextView(activity, categoryDescriptionTextView, null, hasPhoto);
// Match list_item_category_description in list_item.xml
timeDistanceTextView.setSingleLine(false);
@@ -158,8 +148,7 @@ public class ListItemUtils {
// Adjust iconImageView layout gravity
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) iconImageView.getLayoutParams();
params.gravity = timeDistanceTextView.getVisibility() == View.GONE
&& markerCountIcon.getVisibility() == View.GONE ? Gravity.TOP : Gravity.CENTER_VERTICAL;
params.gravity = timeDistanceTextView.getVisibility() == View.GONE && markerCountIcon.getVisibility() == View.GONE ? Gravity.TOP : Gravity.CENTER_VERTICAL;
}
/**
@@ -196,22 +185,17 @@ public class ListItemUtils {
if (isRecording || time == 0L) {
return new String[]{null, null};
}
boolean isToday = DateUtils.isToday(time);
int timeFlags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL;
if (isToday) {
if (useRelativeTime) {
return new String[]{DateUtils.getRelativeTimeSpanString(
time, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE).toString(), null};
} else {
return new String[]{DateUtils.formatDateTime(context, time, timeFlags), null};
}
if (isToday && useRelativeTime) {
return new String[]{DateUtils.getRelativeTimeSpanString(time, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString(), null};
} else if (isToday) {
return new String[]{DateUtils.formatDateTime(context, time, timeFlags), null};
}
return new String[]{DateUtils.formatDateTime(
context, time, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL),
DateUtils.formatDateTime(context, time, timeFlags)};
return new String[]{DateUtils.formatDateTime(context, time, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL), DateUtils.formatDateTime(context, time, timeFlags)};
}
/**
@@ -225,14 +209,15 @@ public class ListItemUtils {
public static void setTextView(Context context, TextView textView, String value, boolean addShadow) {
if (value == null || value.length() == 0) {
textView.setVisibility(View.GONE);
return;
}
textView.setVisibility(View.VISIBLE);
textView.setText(value);
if (addShadow) {
textView.setShadowLayer(5, 0, 2, context.getResources().getColor(android.R.color.black));
} else {
textView.setVisibility(View.VISIBLE);
textView.setText(value);
if (addShadow) {
textView.setShadowLayer(5, 0, 2, context.getResources().getColor(android.R.color.black));
} else {
textView.setShadowLayer(0, 0, 0, 0);
}
textView.setShadowLayer(0, 0, 0, 0);
}
}
@@ -18,30 +18,30 @@ package de.dennisguse.opentracks.util;
import android.location.Location;
import android.util.Log;
import de.dennisguse.opentracks.content.Track;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import de.dennisguse.opentracks.content.Track;
/**
* Utility class for decimating tracks at a given level of precision.
*
* @author Leif Hendrik Wilden
*/
//TODO Cleanup: rename variables
public class LocationUtils {
private static final String TAG = LocationUtils.class.getSimpleName();
// 1 minute in milliseconds
private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S
* UnitConversions.S_TO_MS);
private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
private LocationUtils() {
}
/**
* Computes the distance on the two sphere between the point c0 and the line
* segment c1 to c2.
* Computes the distance on the two sphere between the point c0 and the line segment c1 to c2.
*
* @param c0 the first coordinate
* @param c1 the beginning of the line segment
@@ -64,31 +64,36 @@ public class LocationUtils {
double s2s1lng = s2lng - s1lng;
final double u = ((s0lat - s1lat) * s2s1lat + (s0lng - s1lng) * s2s1lng)
/ (s2s1lat * s2s1lat + s2s1lng * s2s1lng);
if (u <= 0) {
return c0.distanceTo(c1);
}
if (u >= 1) {
return c0.distanceTo(c2);
}
Location sa = new Location("");
sa.setLatitude(c0.getLatitude() - c1.getLatitude());
sa.setLongitude(c0.getLongitude() - c1.getLongitude());
Location sb = new Location("");
sb.setLatitude(u * (c2.getLatitude() - c1.getLatitude()));
sb.setLongitude(u * (c2.getLongitude() - c1.getLongitude()));
return sa.distanceTo(sb);
}
/**
* Decimates the given locations for a given zoom level. This uses a
* Douglas-Peucker decimation algorithm.
* Decimates the given locations for a given zoom level.
* This uses a Douglas-Peucker decimation algorithm.
*
* @param tolerance in meters
* @param locations input
* @param decimated output
*/
private static void decimate(
double tolerance, ArrayList<Location> locations, ArrayList<Location> decimated) {
//TODO What was it used for? Sharing data with other apps?
private static void decimate(double tolerance, List<Location> locations, List<Location> decimated) {
final int n = locations.size();
if (n < 1) {
return;
@@ -153,16 +158,16 @@ public class LocationUtils {
}
/**
* Checks if a given location is a valid (i.e. physically possible) location
* on Earth. Note: The special separator locations (which have latitude = 100)
* will not qualify as valid. Neither will locations with lat=0 and lng=0 as
* these are most likely "bad" measurements which often cause trouble.
* Checks if a given location is a valid (i.e. physically possible) locationon Earth.
* Note: The special separator locations (which have latitude = 100) will not qualify as valid.
* Neither will locations with lat=0 and lng=0 as these are most likely "bad" measurements which often cause trouble.
*
* @param location the location to test
* @return true if the location is a valid location.
*/
public static boolean isValidLocation(Location location) {
return location != null && Math.abs(location.getLatitude()) <= 90
return location != null
&& Math.abs(location.getLatitude()) <= 90
&& Math.abs(location.getLongitude()) <= 180;
}
@@ -172,7 +177,6 @@ public class LocationUtils {
* @param location the location
*/
public static boolean isLocationOld(Location location) {
return !LocationUtils.isValidLocation(location)
|| (System.currentTimeMillis() - location.getTime() > MAX_LOCATION_AGE_MS);
return !LocationUtils.isValidLocation(location) || (System.currentTimeMillis() - location.getTime() > MAX_LOCATION_AGE_MS);
}
}
@@ -31,8 +31,8 @@ import de.dennisguse.opentracks.R;
public class PreferencesUtils {
/*
* Preferences values. The defaults need to match the defaults in the xml
* files.
* Preferences values.
* The defaults need to match the defaults in the xml files.
*/
public static final int AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT = 0;
@@ -48,7 +48,10 @@ public class PreferencesUtils {
public static final boolean CHART_SHOW_HEART_RATE_DEFAULT = true;
public static final boolean CHART_SHOW_POWER_DEFAULT = true;
public static final boolean CHART_SHOW_SPEED_DEFAULT = true;
public static final String CHART_X_AXIS_DEFAULT = "DISTANCE";
@Deprecated
//NOTE: is at the moment still used to determine if a track is currently recorded; better ask the service directly.
//NOTE: This is also used to recover from a reboot, but this data should not be exposed to the whole application.
public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
public static final String DEFAULT_ACTIVITY_DEFAULT = "";
@@ -68,20 +71,16 @@ public class PreferencesUtils {
public static final int RECORDING_GPS_ACCURACY_DEFAULT = 50;
public static final int RECORDING_GPS_ACCURACY_EXCELLENT = 10;
public static final int RECORDING_GPS_ACCURACY_POOR = 2000;
@Deprecated //NOTE: is at the moment still used to determine if a track is currently recorded; better ask the service directly.
public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
public static final boolean RECORDING_TRACK_PAUSED_DEFAULT = true;
public static final int SPLIT_FREQUENCY_DEFAULT = 0;
// Stats
public static final String STATS_RATE_DEFAULT = "SPEED";
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
public static final boolean STATS_SHOW_ELEVATION_DEFAULT = false;
static final boolean STATS_SHOW_ELEVATION_DEFAULT = false;
static final String TRACK_NAME_DEFAULT = "DATE_ISO_8601";
private static final String CHART_X_AXIS_DEFAULT = "DISTANCE";
public static final String STATS_UNITS_DEFAULT = "METRIC";
public static final String TRACK_NAME_DEFAULT = "DATE_ISO_8601";
// Stats
private static final String STATS_RATE_DEFAULT = "SPEED";
public static final boolean SHOW_TRACKDETAIL_WHILE_RECORDING_ON_LOCKSCREEN = false;
@@ -47,10 +47,8 @@ public class StatsUtils {
* Sets the location values.
*
* @param context the context
* @param activity the activity for finding views. If null, the view cannot be
* null
* @param view the containing view for finding views. If null, the activity
* cannot be null
* @param activity the activity for finding views. If null, the view cannot be null
* @param view the containing view for finding views. If null, the activity cannot be null
* @param location the location
* @param isRecording true if recording
*/
@@ -96,19 +94,17 @@ public class StatsUtils {
}
public static void setSensorData(Context context, Activity activity, SensorDataSet sensorDataSet, boolean isRecording) {
{
// SensorDataSet: heart rate
int isVisible = View.VISIBLE;
if (!isRecording || PreferencesUtils.BLUETOOTH_SENSOR_DEFAULT.equals(PreferencesUtils.getString(context, R.string.bluetooth_sensor_key, PreferencesUtils.BLUETOOTH_SENSOR_DEFAULT))) {
isVisible = View.INVISIBLE;
}
getView(activity, null, R.id.stats_sensor_container).setVisibility(isVisible);
// SensorDataSet: heart rate
int isVisible = View.VISIBLE;
if (!isRecording || PreferencesUtils.BLUETOOTH_SENSOR_DEFAULT.equals(PreferencesUtils.getString(context, R.string.bluetooth_sensor_key, PreferencesUtils.BLUETOOTH_SENSOR_DEFAULT))) {
isVisible = View.INVISIBLE;
}
getView(activity, null, R.id.stats_sensor_container).setVisibility(isVisible);
View viewValue = getView(activity, null, R.id.stats_sensor_heart_rate_value);
View viewSensor = getView(activity, null, R.id.stats_sensor_heart_rate_sensor);
if (isRecording) {
setHeartRateData(context, viewValue, viewSensor, sensorDataSet);
}
View viewValue = getView(activity, null, R.id.stats_sensor_heart_rate_value);
View viewSensor = getView(activity, null, R.id.stats_sensor_heart_rate_sensor);
if (isRecording) {
setHeartRateData(context, viewValue, viewSensor, sensorDataSet);
}
}
@@ -126,13 +122,10 @@ public class StatsUtils {
* Sets the trip statistics values.
*
* @param context the context
* @param activity the activity for finding views. If null, then view cannot
* be null
* @param view the containing view for finding views. If null, the activity
* cannot be null
* @param activity the activity for finding views. If null, then view cannot be null
* @param view the containing view for finding views. If null, the activity cannot be null
* @param tripStatistics the trip statistics
* @param trackIconValue the track icon value or null to hide the track icon
* spinner
* @param trackIconValue the track icon value or null to hide the track icon spinner
*/
public static void setTripStatisticsValues(Context context, Activity activity, View view, TripStatistics tripStatistics, String trackIconValue) {
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
@@ -265,8 +258,7 @@ public class StatsUtils {
* @param grade the grade in fraction between 0 and 1
*/
private static void setGradeValue(Context context, View view, int labelId, double grade) {
String value = Double.isNaN(grade) || Double.isInfinite(grade) ? null
: String.format(Locale.getDefault(), GRADE_FORMAT, Math.round(grade * 100));
String value = Double.isNaN(grade) || Double.isInfinite(grade) ? null : String.format(Locale.getDefault(), GRADE_FORMAT, Math.round(grade * 100));
setItem(context, view, labelId, value, GRADE_PERCENTAGE);
}
@@ -279,8 +271,7 @@ public class StatsUtils {
* @param coordinate the coordinate in degrees
*/
private static void setCoordinateValue(Context context, View view, int labelId, double coordinate) {
String value = Double.isNaN(coordinate) || Double.isInfinite(coordinate) ? null
: StringUtils.formatCoordinate(coordinate);
String value = Double.isNaN(coordinate) || Double.isInfinite(coordinate) ? null : StringUtils.formatCoordinate(coordinate);
setItem(context, view, labelId, value, null);
}
@@ -17,13 +17,9 @@ package de.dennisguse.opentracks.util;
import android.content.Context;
import android.location.Location;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.format.DateUtils;
import de.dennisguse.opentracks.R;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -32,6 +28,8 @@ import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.dennisguse.opentracks.R;
/**
* Various string manipulation methods.
*
@@ -41,18 +39,17 @@ import java.util.regex.Pattern;
public class StringUtils {
private static final String COORDINATE_DEGREE = "\u00B0";
private static final SimpleDateFormat ISO_8601_DATE_TIME_FORMAT = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
private static final SimpleDateFormat ISO_8601_BASE = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss", Locale.US);
private static final Pattern ISO_8601_EXTRAS = Pattern.compile(
"^(\\.\\d+)?(?:Z|([+-])(\\d{2}):(\\d{2}))?$");
private static final SimpleDateFormat ISO_8601_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
private static final SimpleDateFormat ISO_8601_BASE = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
private static final Pattern ISO_8601_EXTRAS = Pattern.compile("^(\\.\\d+)?(?:Z|([+-])(\\d{2}):(\\d{2}))?$");
static {
ISO_8601_DATE_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
ISO_8601_BASE.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private StringUtils() {
}
@@ -63,9 +60,8 @@ public class StringUtils {
* @param time the time in milliseconds
*/
public static String formatDateTime(Context context, long time) {
return DateUtils.formatDateTime(
context, time, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE) + " "
+ DateUtils.formatDateTime(context, time, DateUtils.FORMAT_SHOW_TIME);
return DateUtils.formatDateTime(context, time, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE)
+ " " + DateUtils.formatDateTime(context, time, DateUtils.FORMAT_SHOW_TIME);
}
/**
@@ -80,19 +76,20 @@ public class StringUtils {
/**
* Formats the elapsed timed in the form "MM:SS" or "H:MM:SS".
* TODO Remove as min API level is now 21; replace with DateUtils.formatElapsedTime(time * MS_TO_S).
*
* @param time the time in milliseconds
*/
public static String formatElapsedTime(long time) {
DateUtils.formatElapsedTime(1);
/*
* TODO
* Temporary workaround for DateUtils.formatElapsedTime(time * MS_TO_S). In API
* level 17, it returns strings like "1:0:00" instead of "1:00:00", which
* breaks several unit tests.
* Temporary workaround for DateUtils.formatElapsedTime(time * MS_TO_S).
* In API level 17, it returns strings like "1:0:00" instead of "1:00:00", which breaks several unit tests.
*/
if (time < 0) {
return "-";
}
long hours = 0;
long minutes = 0;
long elapsedSeconds = (long) (time * UnitConversions.MS_TO_S);
@@ -135,6 +132,7 @@ public class StringUtils {
if (Double.isNaN(distance) || Double.isInfinite(distance)) {
return context.getString(R.string.value_unknown);
}
if (metricUnits) {
if (distance > 500.0) {
distance *= UnitConversions.M_TO_KM;
@@ -153,11 +151,11 @@ public class StringUtils {
}
}
public static String formatDecimal(double value) {
static String formatDecimal(double value) {
return StringUtils.formatDecimal(value, 2);
}
public static String formatDecimal(double value, int decimalPlaces) {
static String formatDecimal(double value, int decimalPlaces) {
String result = String.format(Locale.getDefault(), "%1$,." + decimalPlaces + "f", value);
return result.replaceAll("[0]*$", "").replaceAll("\\.$", "");
}
@@ -172,14 +170,16 @@ public class StringUtils {
}
/**
* Gets the distance in an array of two strings. The first string is the
* distance. The second string is the unit. The first string is null if the
* distance is invalid.
* Gets the distance in an array of two strings.
* The first string is the distance.
* The second string is the unit.
* The first string is null if the distance is invalid.
*
* @param context the context
* @param distance the distance
* @param metricUnits true to use metric unit
*/
//TODO Return Pair<Distance, Unit>
public static String[] getDistanceParts(Context context, double distance, boolean metricUnits) {
String[] result = new String[2];
if (Double.isNaN(distance) || Double.isInfinite(distance)) {
@@ -211,17 +211,18 @@ public class StringUtils {
}
/**
* Gets the speed in an array of two strings. The first string is the speed.
* The second string is the unit. The first string is null if speed is
* invalid.
* Gets the speed in an array of two strings.
* The first string is the speed.
* The second string is the unit.
* The first string is null if speed is invalid.
*
* @param context the context
* @param speed the speed
* @param metricUnits true to use metric unit
* @param reportSpeed true to report speed
*/
public static String[] getSpeedParts(
Context context, double speed, boolean metricUnits, boolean reportSpeed) {
//TODO Return Pair<Distance, Unit>
public static String[] getSpeedParts(Context context, double speed, boolean metricUnits, boolean reportSpeed) {
String[] result = new String[2];
int unitId;
if (metricUnits) {
@@ -268,7 +269,7 @@ public class StringUtils {
* @param category the category
* @param description the description
*/
public static String getCategoryDescription(String category, String description) {
static String getCategoryDescription(String category, String description) {
if (category == null || category.length() == 0) {
return description;
}
@@ -282,9 +283,9 @@ public class StringUtils {
}
/**
* Formats the given text as a XML CDATA element. This includes adding the
* starting and ending CDATA tags. Please notice that this may result in
* multiple consecutive CDATA tags.
* Formats the given text as a XML CDATA element.
* This includes adding the starting and ending CDATA tags.
* NOTE: This may result in multiple consecutive CDATA tags.
*
* @param text the given text
*/
@@ -293,25 +294,23 @@ public class StringUtils {
}
/**
* Gets the time, in milliseconds, from an XML date time string as defined at
* http://www.w3.org/TR/xmlschema-2/#dateTime
* Gets the time, in milliseconds, from an XML date time string as defined at http://www.w3.org/TR/xmlschema-2/#dateTime
*
* @param xmlDateTime the XML date time string
*/
//TODO Can this be replaced using java.time?
public static long getTime(String xmlDateTime) {
// Parse the date time base
ParsePosition position = new ParsePosition(0);
Date date = ISO_8601_BASE.parse(xmlDateTime, position);
if (date == null) {
throw new IllegalArgumentException("Invalid XML dateTime value: " + xmlDateTime
+ " (at position " + position.getErrorIndex() + ")");
throw new IllegalArgumentException("Invalid XML dateTime value: " + xmlDateTime + " (at position " + position.getErrorIndex() + ")");
}
// Parse the date time extras
Matcher matcher = ISO_8601_EXTRAS.matcher(xmlDateTime.substring(position.getIndex()));
if (!matcher.matches()) {
// This will match even an empty string as all groups are optional. Thus a
// non-match means invalid content.
// This will match even an empty string as all groups are optional. Thus a non-match means invalid content.
throw new IllegalArgumentException("Invalid XML dateTime value: " + xmlDateTime);
}
@@ -354,9 +353,8 @@ public class StringUtils {
}
/**
* Gets the time as an array of three integers. Index 0 contains the number of
* seconds, index 1 contains the number of minutes, and index 2 contains the
* number of hours.
* Gets the time as an array of three integers.
* Index 0 contains the number of seconds, index 1 contains the number of minutes, and index 2 contains the number of hours.
*
* @param time the time in milliseconds
* @return an array of 3 elements.
@@ -379,22 +377,6 @@ public class StringUtils {
return parts;
}
/**
* Gets the html.
*
* @param context the context
* @param resId the string resource id
* @param formatArgs the string resource ids of the format arguments
*/
public static Spanned getHtml(Context context, int resId, Object... formatArgs) {
Object[] args = new Object[formatArgs.length];
for (int i = 0; i < formatArgs.length; i++) {
String url = context.getString((Integer) formatArgs[i]);
args[i] = " <a href='" + url + "'>" + url + "</a> ";
}
return Html.fromHtml(context.getString(resId, args));
}
/**
* Gets the frequency display options.
*
@@ -409,9 +391,7 @@ public class StringUtils {
if (value == PreferencesUtils.FREQUENCY_OFF) {
options[i] = context.getString(R.string.value_off);
} else if (value < 0) {
options[i] = context.getString(
metricUnits ? R.string.value_integer_kilometer : R.string.value_integer_mile,
Math.abs(value));
options[i] = context.getString(metricUnits ? R.string.value_integer_kilometer : R.string.value_integer_mile, Math.abs(value));
} else {
options[i] = context.getString(R.string.value_integer_minute, value);
}
@@ -33,12 +33,12 @@ import android.widget.Spinner;
import androidx.annotation.NonNull;
import de.dennisguse.opentracks.R;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import de.dennisguse.opentracks.R;
/**
* Utilities for track icon.
*
@@ -55,31 +55,16 @@ public class TrackIconUtils {
private static final String SNOW_BOARDING = "SNOW_BOARDING";
private static final String WALK = "WALK";
private static final int[] AIRPLANE_LIST = new int[]{R.string.activity_type_airplane,
R.string.activity_type_commercial_airplane, R.string.activity_type_rc_airplane};
private static final int[] BIKE_LIST = new int[]{R.string.activity_type_biking,
R.string.activity_type_cycling, R.string.activity_type_dirt_bike,
R.string.activity_type_motor_bike, R.string.activity_type_mountain_biking,
R.string.activity_type_road_biking, R.string.activity_type_track_cycling};
private static final int[] BOAT_LIST = new int[]{R.string.activity_type_boat,
R.string.activity_type_ferry, R.string.activity_type_motor_boating,
R.string.activity_type_rc_boat};
private static final int[] DRIVE_LIST = new int[]{R.string.activity_type_atv,
R.string.activity_type_driving, R.string.activity_type_driving_bus,
R.string.activity_type_driving_car};
private static final int[] RUN_LIST = new int[]{R.string.activity_type_running,
R.string.activity_type_street_running, R.string.activity_type_track_running,
R.string.activity_type_trail_running};
private static final int[] SKI_LIST = new int[]{
R.string.activity_type_cross_country_skiing, R.string.activity_type_skiing};
private static final int[] SNOW_BOARDING_LIST = new int[]{
R.string.activity_type_snow_boarding};
private static final int[] WALK_LIST = new int[]{R.string.activity_type_hiking,
R.string.activity_type_off_trail_hiking, R.string.activity_type_speed_walking,
R.string.activity_type_trail_hiking, R.string.activity_type_walking};
private static final int[] AIRPLANE_LIST = new int[]{R.string.activity_type_airplane, R.string.activity_type_commercial_airplane, R.string.activity_type_rc_airplane};
private static final int[] BIKE_LIST = new int[]{R.string.activity_type_biking, R.string.activity_type_cycling, R.string.activity_type_dirt_bike, R.string.activity_type_motor_bike, R.string.activity_type_mountain_biking, R.string.activity_type_road_biking, R.string.activity_type_track_cycling};
private static final int[] BOAT_LIST = new int[]{R.string.activity_type_boat, R.string.activity_type_ferry, R.string.activity_type_motor_boating, R.string.activity_type_rc_boat};
private static final int[] DRIVE_LIST = new int[]{R.string.activity_type_atv, R.string.activity_type_driving, R.string.activity_type_driving_bus, R.string.activity_type_driving_car};
private static final int[] RUN_LIST = new int[]{R.string.activity_type_running, R.string.activity_type_street_running, R.string.activity_type_track_running, R.string.activity_type_trail_running};
private static final int[] SKI_LIST = new int[]{R.string.activity_type_cross_country_skiing, R.string.activity_type_skiing};
private static final int[] SNOW_BOARDING_LIST = new int[]{R.string.activity_type_snow_boarding};
private static final int[] WALK_LIST = new int[]{R.string.activity_type_hiking, R.string.activity_type_off_trail_hiking, R.string.activity_type_speed_walking, R.string.activity_type_trail_hiking, R.string.activity_type_walking};
private static final LinkedHashMap<String, Pair<Integer, Integer>>
MAP = new LinkedHashMap<>();
private static final LinkedHashMap<String, Pair<Integer, Integer>> MAP = new LinkedHashMap<>();
static {
MAP.put(RUN, new Pair<>(R.string.activity_type_running, R.drawable.ic_track_run));
@@ -173,10 +158,8 @@ public class TrackIconUtils {
adapter.notifyDataSetChanged();
}
public static ArrayAdapter<StringBuilder> getIconSpinnerAdapter(
final Context context, String iconValue) {
return new ArrayAdapter<StringBuilder>(context, android.R.layout.simple_spinner_item,
new StringBuilder[]{new StringBuilder(iconValue)}) {
public static ArrayAdapter<StringBuilder> getIconSpinnerAdapter(final Context context, String iconValue) {
return new ArrayAdapter<StringBuilder>(context, android.R.layout.simple_spinner_item, new StringBuilder[]{new StringBuilder(iconValue)}) {
@NonNull
@Override
public View getView(int position, View convertView, @NonNull android.view.ViewGroup parent) {
@@ -211,8 +194,7 @@ public class TrackIconUtils {
* @param menu the menu
*/
public static void setMenuIconColor(Menu menu) {
int size = menu.size();
for (int i = 0; i < size; i++) {
for (int i = 0; i < menu.size(); i++) {
MenuItem menuitem = menu.getItem(i);
setMenuIconColor(menuitem);
}
@@ -32,6 +32,7 @@ import de.dennisguse.opentracks.R;
*/
public class TrackNameUtils {
//TODO Could be available in java.time?
@VisibleForTesting
static final String ISO_8601_FORMAT = "yyyy-MM-dd HH:mm";
@@ -24,14 +24,14 @@ import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackEditActivity;
import de.dennisguse.opentracks.content.WaypointCreationRequest;
import de.dennisguse.opentracks.services.ITrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.R;
import java.util.List;
/**
* Utilities for {@link TrackRecordingServiceConnection}.
@@ -52,6 +52,11 @@ public class TrackRecordingServiceConnectionUtils {
*/
public static boolean isRecordingServiceRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager == null) {
return false;
}
//TODO This approach is deprecated as of API level 26 and should be replaced.
List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo serviceInfo : services) {
@@ -99,13 +104,12 @@ public class TrackRecordingServiceConnectionUtils {
*/
public static void stopRecording(Context context, TrackRecordingServiceConnection trackRecordingServiceConnection, boolean showEditor) {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService != null) {
if (trackRecordingService == null) {
resetRecordingState(context);
} else {
try {
if (showEditor) {
/*
* Need to remember the recordingTrackId before calling
* endCurrentTrack. endCurrentTrack sets the value to -1L.
*/
// Need to remember the recordingTrackId before calling endCurrentTrack() as endCurrentTrack() sets the value to -1L.
long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key);
trackRecordingService.endCurrentTrack();
if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
@@ -118,10 +122,9 @@ public class TrackRecordingServiceConnectionUtils {
trackRecordingService.endCurrentTrack();
}
} catch (Exception e) {
//TODO What exception are we catching here? Should be removed...
Log.e(TAG, "Unable to stop recording.", e);
}
} else {
resetRecordingState(context);
}
trackRecordingServiceConnection.unbindAndStop();
}
@@ -130,8 +133,7 @@ public class TrackRecordingServiceConnectionUtils {
* Resumes the track recording service connection.
*
* @param context the context
* @param trackRecordingServiceConnection the track recording service
* connection
* @param trackRecordingServiceConnection the track recording service connection
*/
public static void startConnection(Context context, TrackRecordingServiceConnection trackRecordingServiceConnection) {
trackRecordingServiceConnection.bindIfStarted();
@@ -143,25 +145,19 @@ public class TrackRecordingServiceConnectionUtils {
private static void resetRecordingState(Context context) {
long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key);
if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
PreferencesUtils.setLong(
context, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
PreferencesUtils.setLong(context, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
}
boolean recordingTrackPaused = PreferencesUtils.getBoolean(context,
R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
boolean recordingTrackPaused = PreferencesUtils.getBoolean(context, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
if (!recordingTrackPaused) {
PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key,
PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
}
}
/**
* Adds a marker.
*/
public static long addMarker(Context context,
TrackRecordingServiceConnection trackRecordingServiceConnection,
WaypointCreationRequest waypointCreationRequest) {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
.getServiceIfBound();
public static long addMarker(Context context, TrackRecordingServiceConnection trackRecordingServiceConnection, WaypointCreationRequest waypointCreationRequest) {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService == null) {
Log.d(TAG, "Unable to add marker, no track recording service");
} else {
@@ -175,6 +171,7 @@ public class TrackRecordingServiceConnectionUtils {
Log.e(TAG, "Unable to add marker.", e);
}
}
Toast.makeText(context, R.string.marker_add_error, Toast.LENGTH_LONG).show();
return -1L;
}
@@ -24,6 +24,7 @@ public class UnitConversions {
// multiplication factor to convert seconds to milliseconds
public static final double S_TO_MS = 1000.0;
// Time
// 1 second in milliseconds
public static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;