mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-09-30 16:52:21 +02:00
GPX: match activity types case-insensitively on import.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ActivityTypeTest {
|
||||
|
||||
@Test
|
||||
public void findBy_id() {
|
||||
assertEquals(ActivityType.TRAIL_RUNNING, ActivityType.findBy("trail running"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_idOfEveryActivityType() {
|
||||
for (ActivityType activityType : ActivityType.values()) {
|
||||
assertEquals(activityType, ActivityType.findBy(activityType.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_synonymsOfEveryActivityType() {
|
||||
for (ActivityType activityType : ActivityType.values()) {
|
||||
for (String synonym : activityType.synonyms) {
|
||||
assertEquals(activityType, ActivityType.findBy(synonym));
|
||||
assertEquals(activityType, ActivityType.findBy(synonym.toUpperCase(Locale.ROOT).replace(' ', '_')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_ignoresCase() {
|
||||
assertEquals(ActivityType.RUNNING, ActivityType.findBy("RUNNING"));
|
||||
assertEquals(ActivityType.ATV, ActivityType.findBy("atv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_ignoresSeparators() {
|
||||
assertEquals(ActivityType.TRAIL_RUNNING, ActivityType.findBy("TRAIL_RUNNING"));
|
||||
assertEquals(ActivityType.MOUNTAIN_BIKING, ActivityType.findBy("mountain-biking"));
|
||||
assertEquals(ActivityType.CROSS_COUNTRY_SKIING, ActivityType.findBy("cross_country_skiing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_ignoresSurroundingAndRepeatedWhitespace() {
|
||||
assertEquals(ActivityType.MOUNTAIN_BIKING, ActivityType.findBy(" Mountain Biking "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_synonym() {
|
||||
assertEquals(ActivityType.RUNNING, ActivityType.findBy("treadmill"));
|
||||
assertEquals(ActivityType.TRAIL_RUNNING, ActivityType.findBy("TRAIL_RUN"));
|
||||
assertEquals(ActivityType.MOUNTAIN_BIKING, ActivityType.findBy("MOUNTAIN_BIKE"));
|
||||
assertEquals(ActivityType.SWIMMING_OPEN, ActivityType.findBy("SWIMMING_OPENWATER"));
|
||||
assertEquals(ActivityType.BIKING, ActivityType.findBy("bike"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_unknown() {
|
||||
assertEquals(ActivityType.UNKNOWN, ActivityType.findBy("hovercraft"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_null() {
|
||||
assertEquals(ActivityType.UNKNOWN, ActivityType.findBy(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findBy_blank() {
|
||||
assertEquals(ActivityType.UNKNOWN, ActivityType.findBy(" "));
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
|
||||
@@ -14,13 +15,13 @@ public enum ActivityType {
|
||||
|
||||
AIRPLANE("airplane", R.string.activity_type_airplane, R.drawable.ic_activity_flight_24dp, true),
|
||||
ATV("ATV", R.string.activity_type_atv, R.drawable.ic_activity_drive_24dp, true),
|
||||
BIKING("biking", R.string.activity_type_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
BIKING("biking", List.of("bike", "indoor cycling"), R.string.activity_type_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
BLIMP("blimp", R.string.activity_type_blimp, ActivityIcon.ICON_UNKNOWN, true),
|
||||
BOAT("boat", R.string.activity_type_boat, R.drawable.ic_activity_boat_24dp, true),
|
||||
CLIMBING("climbing", R.string.activity_type_climbing, R.drawable.ic_activity_climbing_24dp, false),
|
||||
COMMERCIAL_AIRPLANE("commercial airplane", R.string.activity_type_commercial_airplane, R.drawable.ic_activity_flight_24dp, true),
|
||||
CROSS_COUNTRY_SKIING("cross-country skiing", R.string.activity_type_cross_country_skiing, R.drawable.ic_activity_skiing_24dp, true),
|
||||
CYCLING("cycling", R.string.activity_type_cycling, R.drawable.ic_activity_bike_24dp, true),
|
||||
CYCLING("cycling", List.of("cycle"), R.string.activity_type_cycling, R.drawable.ic_activity_bike_24dp, true),
|
||||
DIRT_BIKE("dirt bike", R.string.activity_type_dirt_bike, R.drawable.ic_activity_mtb_24dp, true),
|
||||
DONKEY_BACK_RIDING("donkey back riding", R.string.activity_type_donkey_back_riding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
DRIVING("driving", R.string.activity_type_driving, R.drawable.ic_activity_drive_24dp, true),
|
||||
@@ -30,21 +31,21 @@ public enum ActivityType {
|
||||
FERRY("ferry", R.string.activity_type_ferry, R.drawable.ic_activity_boat_24dp, true),
|
||||
FRISBEE("frisbee", R.string.activity_type_frisbee, ActivityIcon.ICON_UNKNOWN, true),
|
||||
GLIDING("gliding", R.string.activity_type_gliding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
GRAVEL_BIKING("gravel biking", R.string.activity_type_gravel_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
GRAVEL_BIKING("gravel biking", List.of("gravel bike"), R.string.activity_type_gravel_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
HANG_GLIDING("hang gliding", R.string.activity_type_hang_gliding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
HELICOPTER("helicopter", R.string.activity_type_helicopter, ActivityIcon.ICON_UNKNOWN, true),
|
||||
HIKING("hiking", R.string.activity_type_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
HIKING("hiking", List.of("hike"), R.string.activity_type_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
HORSE_BACK_RIDING("horse back riding", R.string.activity_type_horse_back_riding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
HOT_AIR_BALLOON("hot air balloon", R.string.activity_type_hot_air_balloon, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ICE_SAILING("ice sailing", R.string.activity_type_ice_sailing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
INLINE_SKATING("inline skating", R.string.activity_type_inline_skating, R.drawable.ic_activity_inline_skating_24dp, true),
|
||||
INLINE_SKATING("inline skating", List.of("inline skate"), R.string.activity_type_inline_skating, R.drawable.ic_activity_inline_skating_24dp, true),
|
||||
KAYAKING("kayaking", R.string.activity_type_kayaking, R.drawable.ic_activity_kayaking_24dp, true),
|
||||
KITE_SURFING("kite surfing", R.string.activity_type_kite_surfing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
LAND_SAILING("land sailing", R.string.activity_type_land_sailing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
MIXED_TYPE("mixed type", R.string.activity_type_mixed_type, ActivityIcon.ICON_UNKNOWN, true),
|
||||
MOTOR_BIKE("motor bike", R.string.activity_type_motor_bike, R.drawable.ic_activity_motorbike_24dp, true),
|
||||
MOTOR_BOATING("motor boating", R.string.activity_type_motor_boating, R.drawable.ic_activity_boat_24dp, true),
|
||||
MOUNTAIN_BIKING("mountain biking", R.string.activity_type_mountain_biking, R.drawable.ic_activity_mtb_24dp, true),
|
||||
MOUNTAIN_BIKING("mountain biking", List.of("mountain bike"), R.string.activity_type_mountain_biking, R.drawable.ic_activity_mtb_24dp, true),
|
||||
OFF_TRAIL_HIKING("off trail hiking", R.string.activity_type_off_trail_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
OTHER("other", R.string.activity_type_other, ActivityIcon.ICON_UNKNOWN, true),
|
||||
PADDLING("paddling", R.string.activity_type_paddling, ActivityIcon.ICON_UNKNOWN, true),
|
||||
@@ -53,46 +54,57 @@ public enum ActivityType {
|
||||
RC_BOAT("RC boat", R.string.activity_type_rc_boat, R.drawable.ic_activity_boat_24dp, true),
|
||||
RC_HELICOPTER("RC helicopter", R.string.activity_type_rc_helicopter, ActivityIcon.ICON_UNKNOWN, true),
|
||||
RIDING("riding", R.string.activity_type_horse_back_riding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ROAD_BIKING("road biking", R.string.activity_type_road_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
ROAD_BIKING("road biking", List.of("road bike"), R.string.activity_type_road_biking, R.drawable.ic_activity_bike_24dp, true),
|
||||
ROLLER_SKIING("roller skiing", R.string.activity_type_roller_skiing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ROWING("rowing", R.string.activity_type_rowing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
RUNNING("running", R.string.activity_type_running, R.drawable.ic_activity_run_24dp, false),
|
||||
RUNNING("running", List.of("run", "treadmill"), R.string.activity_type_running, R.drawable.ic_activity_run_24dp, false),
|
||||
SAILING("sailing", R.string.activity_type_sailing, R.drawable.ic_activity_sailing_24dp, true),
|
||||
KICKSCOOTER("kickscooter", R.string.activity_type_kickscooter, R.drawable.ic_activity_scooter_24dp, true),
|
||||
SEAPLANE("seaplane", R.string.activity_type_seaplane, R.drawable.ic_activity_flight_24dp, true),
|
||||
SKATE_BOARDING("skateboarding", R.string.activity_type_skate_boarding, R.drawable.ic_activity_skateboarding_24dp, true),
|
||||
SKATE_BOARDING("skateboarding", List.of("skateboard"), R.string.activity_type_skate_boarding, R.drawable.ic_activity_skateboarding_24dp, true),
|
||||
SKATING("skating", R.string.activity_type_skating, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SKIING("skiing", R.string.activity_type_skiing, R.drawable.ic_activity_skiing_24dp, true),
|
||||
SKY_JUMPING("sky jumping", R.string.activity_type_sky_jumping, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SLED("sled", R.string.activity_type_sled, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SNOW_BOARDING("snowboarding", R.string.activity_type_snow_boarding, R.drawable.ic_activity_snowboarding_24dp, true),
|
||||
SNOW_BOARDING("snowboarding", List.of("snowboard"), R.string.activity_type_snow_boarding, R.drawable.ic_activity_snowboarding_24dp, true),
|
||||
SNOW_SHOEING("snow shoeing", R.string.activity_type_snow_shoeing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SPEED_WALKING("speed walking", R.string.activity_type_speed_walking, R.drawable.ic_activity_walk_24dp, false),
|
||||
STREET_RUNNING("street running", R.string.activity_type_street_running, R.drawable.ic_activity_run_24dp, false),
|
||||
SURFING("surfing", R.string.activity_type_surfing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
TRACK_CYCLING("track cycling", R.string.activity_type_track_cycling, R.drawable.ic_activity_bike_24dp, true),
|
||||
TRACK_RUNNING("track running", R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRACK_RUNNING("track running", List.of("track run"), R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRAIL_HIKING("trail hiking", R.string.activity_type_trail_hiking, R.drawable.ic_activity_walk_24dp, false),
|
||||
TRAIL_RUNNING("trail running", R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRAIL_RUNNING("trail running", List.of("trail run"), R.string.activity_type_trail_running, R.drawable.ic_activity_run_24dp, false),
|
||||
TRAIN("train", R.string.activity_type_train, ActivityIcon.ICON_UNKNOWN, true),
|
||||
ULTIMATE_FRISBEE("ultimate frisbee", R.string.activity_type_ultimate_frisbee, ActivityIcon.ICON_UNKNOWN, true),
|
||||
WAKEBOARDING("wakeboarding", R.string.activity_type_wakeboarding, ActivityIcon.ICON_UNKNOWN, true),
|
||||
WALKING("walking", R.string.activity_type_walking, R.drawable.ic_activity_walk_24dp, false),
|
||||
WALKING("walking", List.of("walk"), R.string.activity_type_walking, R.drawable.ic_activity_walk_24dp, false),
|
||||
WATER_SKIING("water skiing", R.string.activity_type_water_skiing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
WIND_SURFING("wind surfing", R.string.activity_type_wind_surfing, ActivityIcon.ICON_UNKNOWN, true),
|
||||
SWIMMING("swimming", R.string.activity_type_swimming, R.drawable.ic_activity_swimming_24dp, false),
|
||||
SWIMMING_OPEN("swimming in open water", R.string.activity_type_swimming_open, R.drawable.ic_activity_swimming_open_24dp, false),
|
||||
SWIMMING("swimming", List.of("swim"), R.string.activity_type_swimming, R.drawable.ic_activity_swimming_24dp, false),
|
||||
SWIMMING_OPEN("swimming in open water", List.of("swimming openwater", "open water swimming"), R.string.activity_type_swimming_open, R.drawable.ic_activity_swimming_open_24dp, false),
|
||||
WORKOUT("workout", R.string.activity_type_workout, R.drawable.ic_activity_workout_24dp, false),
|
||||
UNKNOWN("unknown", R.string.activity_type_unknown, ActivityIcon.ICON_UNKNOWN, true);
|
||||
|
||||
final String id;
|
||||
|
||||
/**
|
||||
* Spellings used by other applications that {@link #normalize(String)} cannot map onto {@link #id}.
|
||||
* Already normalized.
|
||||
*/
|
||||
final List<String> synonyms;
|
||||
|
||||
final int iconDrawableId;
|
||||
final boolean showSpeedPreferred;
|
||||
final int localizedStringId;
|
||||
|
||||
ActivityType(String id, int localizedStringId, int iconDrawableId, boolean showSpeedPreferred) {
|
||||
this(id, List.of(), localizedStringId, iconDrawableId, showSpeedPreferred);
|
||||
}
|
||||
|
||||
ActivityType(String id, List<String> synonyms, int localizedStringId, int iconDrawableId, boolean showSpeedPreferred) {
|
||||
this.id = id;
|
||||
this.synonyms = synonyms;
|
||||
this.localizedStringId = localizedStringId;
|
||||
this.iconDrawableId = iconDrawableId;
|
||||
this.showSpeedPreferred = showSpeedPreferred;
|
||||
@@ -121,12 +133,39 @@ public enum ActivityType {
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowercases and reduces "_", "-" and whitespace runs to a single space.
|
||||
* Lowercasing is locale-independent: under a Turkish locale the I of "RUNNING" would otherwise
|
||||
* lowercase to a dotless i and stop matching "running".
|
||||
*/
|
||||
@NonNull
|
||||
private static String normalize(String activityTypeId) {
|
||||
if (activityTypeId == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return activityTypeId.toLowerCase(Locale.ROOT)
|
||||
.replaceAll("[\\s_-]+", " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an activity type as written by another application; GPX's type element is free text.
|
||||
*/
|
||||
@NonNull
|
||||
public static ActivityType findBy(String activityTypeId) {
|
||||
return Arrays.stream(ActivityType.values()).filter(
|
||||
it -> it.id.equals(activityTypeId)
|
||||
).findFirst()
|
||||
.orElse(ActivityType.UNKNOWN);
|
||||
String normalized = normalize(activityTypeId);
|
||||
if (normalized.isEmpty()) {
|
||||
return ActivityType.UNKNOWN;
|
||||
}
|
||||
|
||||
return Arrays.stream(ActivityType.values())
|
||||
.filter(it -> normalize(it.id).equals(normalized))
|
||||
.findFirst()
|
||||
.orElseGet(() -> Arrays.stream(ActivityType.values())
|
||||
.filter(it -> it.synonyms.contains(normalized))
|
||||
.findFirst()
|
||||
.orElse(ActivityType.UNKNOWN));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
Reference in New Issue
Block a user