diff --git a/CHANGELOG.md b/CHANGELOG.md index aaf49da0d..96f2b4f0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Mapbox welcomes participation and contributions from everyone. ### main +- Added `RouteLeg#notifications`. ### v7.6.0 - August 01, 2025 diff --git a/samples/src/main/java/com/mapbox/samples/BasicRouteNotification.java b/samples/src/main/java/com/mapbox/samples/BasicRouteNotification.java new file mode 100644 index 000000000..2bb28e0b6 --- /dev/null +++ b/samples/src/main/java/com/mapbox/samples/BasicRouteNotification.java @@ -0,0 +1,47 @@ +package com.mapbox.samples; + +import com.mapbox.api.directions.v5.DirectionsCriteria; +import com.mapbox.api.directions.v5.MapboxDirections; +import com.mapbox.api.directions.v5.models.DirectionsResponse; +import com.mapbox.api.directions.v5.models.Notification; +import com.mapbox.api.directions.v5.models.RouteOptions; +import com.mapbox.sample.BuildConfig; +import retrofit2.Response; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +public class BasicRouteNotification { + + public static void main(String[] args) throws IOException { + simpleMapboxDirectionsRequest(); + } + + private static void simpleMapboxDirectionsRequest() throws IOException { + MapboxDirections.Builder builder = MapboxDirections.builder(); + + // 1. Pass in all the required information to get a simple directions route. + RouteOptions routeOptions = RouteOptions.builder() + .user("") // the user which has route notifications enabled + .profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC) + .coordinates("-115.5747924943478,49.58740426100405;-115.33330133850265,49.444367698479994") + .steps(true) + .overview(DirectionsCriteria.OVERVIEW_FULL) + .geometries(DirectionsCriteria.GEOMETRY_POLYLINE6) + .excludeList(Arrays.asList(DirectionsCriteria.EXCLUDE_UNPAVED)) + .build(); + builder.routeOptions(routeOptions); + builder.accessToken(BuildConfig.MAPBOX_ACCESS_TOKEN); + + // 2. That's it! Now execute the command and get the response. + Response response = builder.build().executeCall(); + + // 3. Log information from the response + System.out.println("Check that the GET response is successful " + response.isSuccessful()); + if (response.isSuccessful()) { + List notifications = response.body().routes().get(0).legs().get(0).notifications(); + System.out.println("Notifications: " + notifications); + } + } +} diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java index de73a4c65..a17218839 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java @@ -3,6 +3,9 @@ import androidx.annotation.IntDef; import androidx.annotation.StringDef; import com.mapbox.api.directions.v5.models.Amenity; +import com.mapbox.api.directions.v5.models.Notification; +import com.mapbox.api.directions.v5.models.RouteLeg; +import com.mapbox.api.directions.v5.models.RouteOptions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -495,6 +498,176 @@ public final class DirectionsCriteria { */ public static final String AMENITY_TYPE_FAX = "FAX"; + /** + * Violation notification type. {@link Notification#type()} will have this value + * if some request parameters were violated. + */ + public static final String NOTIFICATION_TYPE_VIOLATION = "violation"; + + /** + * Alert notification type. {@link Notification#type()} will have this value + * if some implicit route preferences cannot be satisfied + */ + public static final String NOTIFICATION_TYPE_ALERT = "alert"; + + /** + * A notification that is received with the initial route request or during one of the route + * refreshes, but is then kept constant and not updated on route refreshes. + * It persists until arrival. + * An example is a violation alert, where the condition is unlikely to change. + * {@link Notification#refreshType()} will have this value + */ + public static final String NOTIFICATION_REFRESH_TYPE_STATIC = "static"; + + /** + * A notification that is updated and reset with each route refresh. + * Previous notifications of this type are cleared, + * and new ones are applied based on the current status. + * This type of notification is used for information that can change, + * such as the status of a busy EV station. + * {@link Notification#refreshType()} will have this value + */ + public static final String NOTIFICATION_REFRESH_TYPE_DYNAMIC = "dynamic"; + + /** + * Max height notification subtype of type {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#maxHeight()} parameter is violated. + */ + public static final String NOTIFICATION_SUBTYPE_MAX_HEIGHT = "maxHeight"; + + /** + * Max width notification subtype of type {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#maxWidth()} parameter is violated. + */ + public static final String NOTIFICATION_SUBTYPE_MAX_WIDTH = "maxWidth"; + + /** + * Max weight notification subtype of type {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#maxWeight()} parameter is violated. + */ + public static final String NOTIFICATION_SUBTYPE_MAX_WEIGHT = "maxWeight"; + + /** + * Unpaved notification subtype of type {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#exclude()} parameter with value + * {@link DirectionsCriteria#EXCLUDE_UNPAVED} is violated. + */ + public static final String NOTIFICATION_SUBTYPE_UNPAVED = "unpaved"; + + /** + * Point exclusion notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#exclude()} parameter with point value is violated. + */ + public static final String NOTIFICATION_SUBTYPE_POINT_EXCLUSION = "pointExclusion"; + + /** + * Country border exclusion notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#exclude()} parameter "country_border" is violated. + *

+ * Country border notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT}. + * {@link Notification#subtype()} will have this value if route crosses a country border. + */ + public static final String NOTIFICATION_SUBTYPE_COUNTRY_BORDER_CROSSING = "countryBorderCrossing"; + + /** + * State border exclusion notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#exclude()} parameter "state_border" is violated. + *

+ * State border notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT}. + * {@link Notification#subtype()} will have this value if route crosses a state border. + */ + public static final String NOTIFICATION_SUBTYPE_STATE_BORDER_CROSSING = "stateBorderCrossing"; + + /** + * EV minimal charge at charging station notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if route request is EV (engine=electric) and EV's battery charge level was less + * than requested at a charging station. + */ + public static final String NOTIFICATION_SUBTYPE_EV_MIN_CHARGE_AT_CHARGING_STATION + = "evMinChargeAtChargingStation"; + + /** + * EV minimal charge at charging station notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if route request is EV (engine=electric) and EV's battery charge level was less + * than requested at a destination + */ + public static final String NOTIFICATION_SUBTYPE_EV_MIN_CHARGE_AT_DESTINATION + = "evMinChargeAtDestination"; + + /** + * Tunnel notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION}. + * {@link Notification#subtype()} will have this value + * if {@link RouteOptions#exclude()} tunnel parameter is violated. + *

+ * Tunnel notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT}. + * {@link Notification#subtype()} will have this value if route has a tunnel + */ + public static final String NOTIFICATION_SUBTYPE_TUNNEL = "tunnel"; + + /** + * EV insufficient charge notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT}. + * {@link Notification#subtype()} will have this value if route request is EV (engine=electric) + * and EV's battery charge level transitioned from a positive value to zero or less for the first + * time on a leg. Note that if a leg starts with zero charge level the notification is not + * emitted. + */ + public static final String NOTIFICATION_SUBTYPE_EV_INSUFFICIENT_CHARGE = "evInsufficientCharge"; + + /** + * Station unavailable notification subtype of type + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT}. + * {@link Notification#subtype()} will have this value if route request is EV (engine=electric) + * and the station offered during trip planning became unavailable. + * The reason for availability change is provided in field {@link Notification#reason()} and + * can be either {@link DirectionsCriteria#NOTIFICATION_EV_STATION_OUT_OF_ORDER} + * (when station broke down) or {@link DirectionsCriteria#NOTIFICATION_EV_STATION_OCCUPIED} + * (when there are no available chargers at the station) + */ + public static final String NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE = "stationUnavailable"; + + /** + * Out of order reason for unavailability of the charging station for the electric vehicle. + * {@link Notification#reason()} will have this value if route request is EV (engine=electric) + * and the station offered during trip planning became unavailable. + */ + public static final String NOTIFICATION_EV_STATION_OUT_OF_ORDER = "outOfOrder"; + + /** + * `Occupied` reason for unavailability of the charging station for the electric vehicle. + * {@link Notification#reason()} will have this value if route request is EV (engine=electric) + * and the station offered during trip planning became unavailable. + */ + public static final String NOTIFICATION_EV_STATION_OCCUPIED = "occupied"; + + /** + * Include all notifications in the route response (see {@link RouteLeg#notifications()}). + */ + public static final String NOTIFICATION_FLOW_ALL = "all"; + + /** + * Include none of the notifications in the route response (see {@link RouteLeg#notifications()}). + */ + public static final String NOTIFICATION_FLOW_NONE = "none"; + private DirectionsCriteria() { //not called } @@ -505,7 +678,7 @@ private DirectionsCriteria() { * @since 3.0.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ PROFILE_DRIVING_TRAFFIC, PROFILE_DRIVING, PROFILE_WALKING, @@ -520,7 +693,7 @@ private DirectionsCriteria() { * @since 3.0.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ GEOMETRY_POLYLINE, GEOMETRY_POLYLINE6 }) @@ -533,7 +706,7 @@ private DirectionsCriteria() { * @since 3.0.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ OVERVIEW_FALSE, OVERVIEW_FULL, OVERVIEW_SIMPLIFIED @@ -547,7 +720,7 @@ private DirectionsCriteria() { * @since 3.0.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ ANNOTATION_DURATION, ANNOTATION_DISTANCE, ANNOTATION_SPEED, @@ -569,7 +742,7 @@ private DirectionsCriteria() { */ @Retention(RetentionPolicy.CLASS) // Please update Exclude.VALID_EXCLUDE_CRITERIA adding new type of exclude - @StringDef( { + @StringDef({ EXCLUDE_FERRY, EXCLUDE_MOTORWAY, EXCLUDE_TOLL, @@ -585,7 +758,7 @@ private DirectionsCriteria() { * Retention policy for include key. */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ INCLUDE_HOV2, INCLUDE_HOV3, INCLUDE_HOT @@ -599,7 +772,7 @@ private DirectionsCriteria() { * @since 0.3.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ IMPERIAL, METRIC, BRITISH_IMPERIAL @@ -613,7 +786,7 @@ private DirectionsCriteria() { * @since 3.0.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ SOURCE_ANY, SOURCE_FIRST }) @@ -626,21 +799,20 @@ private DirectionsCriteria() { * @since 3.0.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ DESTINATION_ANY, DESTINATION_LAST }) public @interface DestinationCriteria { } - /** * Retention policy for the approaches parameter in the MapMatching and Directions API. * * @since 3.2.0 */ @Retention(RetentionPolicy.CLASS) - @StringDef( { + @StringDef({ APPROACH_UNRESTRICTED, APPROACH_CURB }) @@ -716,4 +888,69 @@ private DirectionsCriteria() { }) public @interface AmenityTypeCriteria { } + + /** + * Supported notification types. See {@link Notification#type()}. + */ + @Retention(RetentionPolicy.CLASS) + @StringDef({ + NOTIFICATION_TYPE_VIOLATION, + NOTIFICATION_TYPE_ALERT + }) + public @interface NotificationsTypeCriteria { + } + + /** + * Supported notification refresh types. See {@link Notification#refreshType()}. + */ + @Retention(RetentionPolicy.CLASS) + @StringDef({ + NOTIFICATION_REFRESH_TYPE_STATIC, + NOTIFICATION_REFRESH_TYPE_DYNAMIC + }) + public @interface NotificationsRefreshTypeCriteria { + } + + /** + * Supported notification subtypes. See {@link Notification#subtype()}. + */ + @Retention(RetentionPolicy.CLASS) + @StringDef({ + NOTIFICATION_SUBTYPE_MAX_HEIGHT, + NOTIFICATION_SUBTYPE_MAX_WIDTH, + NOTIFICATION_SUBTYPE_MAX_WEIGHT, + NOTIFICATION_SUBTYPE_UNPAVED, + NOTIFICATION_SUBTYPE_POINT_EXCLUSION, + NOTIFICATION_SUBTYPE_COUNTRY_BORDER_CROSSING, + NOTIFICATION_SUBTYPE_STATE_BORDER_CROSSING, + NOTIFICATION_SUBTYPE_EV_MIN_CHARGE_AT_CHARGING_STATION, + NOTIFICATION_SUBTYPE_EV_MIN_CHARGE_AT_DESTINATION, + NOTIFICATION_SUBTYPE_TUNNEL, + NOTIFICATION_SUBTYPE_EV_INSUFFICIENT_CHARGE, + NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE + }) + public @interface NotificationsSubtypeCriteria { + } + + /** + * Supported EV station unavailable reasons. See {@link Notification#reason()}. + */ + @Retention(RetentionPolicy.CLASS) + @StringDef({ + NOTIFICATION_EV_STATION_OUT_OF_ORDER, + NOTIFICATION_EV_STATION_OCCUPIED + }) + public @interface NotificationsEvStationUnavailableReasonCriteria { + } + + /** + * Supported {@link RouteOptions#notifications()} parameter values. + */ + @Retention(RetentionPolicy.CLASS) + @StringDef({ + NOTIFICATION_FLOW_ALL, + NOTIFICATION_FLOW_NONE, + }) + public @interface NotificationsFlowCriteria { + } } diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/Notification.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/Notification.java new file mode 100644 index 000000000..8ae2ffba2 --- /dev/null +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/Notification.java @@ -0,0 +1,291 @@ +package com.mapbox.api.directions.v5.models; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.auto.value.AutoValue; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.SerializedName; +import com.mapbox.api.directions.v5.DirectionsAdapterFactory; +import com.mapbox.api.directions.v5.DirectionsCriteria; + +/** + * Class containing information about route notification. See {@link RouteLeg#notifications()}. + */ +@AutoValue +public abstract class Notification extends DirectionsJsonObject { + + /** + * Create a new instance of this class by using the {@link Builder} class. + * + * @return this classes {@link Builder} for creating a new instance + */ + public static Builder builder() { + return new AutoValue_Notification.Builder(); + } + + /** + * Notification type. Can be one of {@link DirectionsCriteria.NotificationsTypeCriteria}. + * + * @return notification type + */ + @NonNull + @DirectionsCriteria.NotificationsTypeCriteria + public abstract String type(); + + /** + * Notification refresh type. + * Can be one of {@link DirectionsCriteria.NotificationsRefreshTypeCriteria}. + * + * @return notification refresh type + */ + @SerializedName("refresh_type") + @NonNull + @DirectionsCriteria.NotificationsRefreshTypeCriteria + public abstract String refreshType(); + + /** + * Notification subtype. Can be one of {@link DirectionsCriteria.NotificationsSubtypeCriteria}, + * depending on {@link Notification#type()}. + * + * @return notification subtype + */ + @Nullable + @DirectionsCriteria.NotificationsSubtypeCriteria + public abstract String subtype(); + + /** + * Leg-wise start index of the area that violates the request parameter. + * This value is present only for + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_COUNTRY_BORDER_CROSSING}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_STATE_BORDER_CROSSING} + * otherwise it is null + * + * @return start index + */ + @SerializedName("geometry_index_start") + @Nullable + public abstract Integer geometryIndexStart(); + + /** + * Leg-wise position in the coordinate list where the notification occurred, relative to the + * start of the leg it's on. + * + * This value is present only for + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_EV_INSUFFICIENT_CHARGE} otherwise it is null. + * + * @return index position in the coordinate list + */ + @SerializedName("geometry_index") + @Nullable + public abstract Integer geometryIndex(); + + /** + * Leg-wise end index of the area that violates the request parameter. + * This value is present only for + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_COUNTRY_BORDER_CROSSING}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_STATE_BORDER_CROSSING} + * otherwise it is null + * + * @return end index + */ + @SerializedName("geometry_index_end") + @Nullable + public abstract Integer geometryIndexEnd(); + + /** + * Notification details specific to {@link Notification#type()} + * and {@link Notification#subtype()}. + * + * @return notification details + */ + @Nullable + public abstract NotificationDetails details(); + + /** + * Notification reason. It is valid only if {@link Notification#type()} is + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT} and {@link Notification#subtype()} is + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE}. + * + * @return reason for the unavailability of the charging station for the electric vehicle + */ + @DirectionsCriteria.NotificationsEvStationUnavailableReasonCriteria + @Nullable + public abstract String reason(); + + + /** + * Notification charging station id. It is valid only if {@link Notification#type()} is + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT} and {@link Notification#subtype()} is + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE}. + * + * @return charging station id of the unavailable charging station for the electric vehicle + */ + @Nullable + @SerializedName("station_id") + public abstract String chargingStationId(); + + /** + * Convert the current {@link Notification} to its builder holding the currently assigned + * values. This allows you to modify a single property and then rebuild the object resulting in + * an updated and modified {@link Notification}. + * + * @return a {@link Builder} with the same values set to match the ones defined + * in this {@link Notification} + */ + public abstract Builder toBuilder(); + + /** + * Gson type adapter for parsing Gson to this class. + * + * @param gson the built {@link Gson} object + * @return the type adapter for this class + */ + public static TypeAdapter typeAdapter(Gson gson) { + return new AutoValue_Notification.GsonTypeAdapter(gson); + } + + /** + * Create a new instance of this class by passing in a formatted valid JSON String. + * + * @param json a formatted valid JSON string defining a Notification + * @return a new instance of this class defined by the values passed inside this static factory + * method + */ + public static Notification fromJson(String json) { + GsonBuilder gson = new GsonBuilder(); + gson.registerTypeAdapterFactory(DirectionsAdapterFactory.create()); + return gson.create().fromJson(json, Notification.class); + } + + /** + * This builder can be used to set the values describing the {@link Notification}. + */ + @AutoValue.Builder + public abstract static class Builder extends DirectionsJsonObject.Builder { + + /** + * Notification type. Can be one of {@link DirectionsCriteria.NotificationsTypeCriteria}. + * + * @param type notification type + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder type( + @NonNull @DirectionsCriteria.NotificationsTypeCriteria String type + ); + + /** + * Notification refresh type. + * Can be one of {@link DirectionsCriteria.NotificationsRefreshTypeCriteria}. + * + * @param type notification refresh type + * @return this builder for chaining options together + */ + @SerializedName("refresh_type") + @NonNull + public abstract Builder refreshType( + @NonNull @DirectionsCriteria.NotificationsRefreshTypeCriteria String type + ); + + /** + * Notification subtype. Can be one of {@link DirectionsCriteria.NotificationsSubtypeCriteria}, + * depending on {@link Notification.Builder#type()}. + * + * @param subtype notification subtype + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder subtype( + @Nullable @DirectionsCriteria.NotificationsSubtypeCriteria String subtype + ); + + /** + * Leg-wise start index of the area that violates the request parameter. + * + * @param geometryIndexStart start index + * @return this builder for chaining options together + */ + @SerializedName("geometry_index_start") + @NonNull + public abstract Builder geometryIndexStart(@Nullable Integer geometryIndexStart); + + + /** + * Leg-wise position in the coordinate list where the notification occurred, relative to the + * start of the leg it's on. + * + * @param geometryIndex index + * @return this builder for chaining options together + */ + @SerializedName("geometry_index") + @NonNull + public abstract Builder geometryIndex(@Nullable Integer geometryIndex); + + /** + * Leg-wise end index of the area that violates the request parameter. + * + * @param geometryIndexEnd end index + * @return this builder for chaining options together + */ + @SerializedName("geometry_index_end") + @NonNull + public abstract Builder geometryIndexEnd(@Nullable Integer geometryIndexEnd); + + /** + * Notification details. + * + * @param details notification details + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder details(@Nullable NotificationDetails details); + + /** + * Notification reason. It is valid only if {@link Notification#type()} is + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT} and {@link Notification#subtype()} is + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE}. + * + * @param reason for the unavailability of the charging station for the electric vehicle. Can be + * one of {@link DirectionsCriteria.NotificationsEvStationUnavailableReasonCriteria}. + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder reason( + @Nullable @DirectionsCriteria.NotificationsEvStationUnavailableReasonCriteria String reason + ); + + /** + * Notification charging station id. It is valid only if {@link Notification#type()} is + * {@link DirectionsCriteria#NOTIFICATION_TYPE_ALERT} and {@link Notification#subtype()} is + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE}. + * + * @param id of the unavailable charging station for the electric vehicle + * @return this builder for chaining options together + */ + @SerializedName("station_id") + @NonNull + public abstract Builder chargingStationId( + @Nullable String id + ); + + /** + * Build a new {@link Notification} object. + * + * @return a new {@link Notification} using the provided values in this builder + */ + @NonNull + public abstract Notification build(); + } +} diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/NotificationDetails.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/NotificationDetails.java new file mode 100644 index 000000000..b07a8fbbd --- /dev/null +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/NotificationDetails.java @@ -0,0 +1,208 @@ +package com.mapbox.api.directions.v5.models; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.auto.value.AutoValue; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.SerializedName; +import com.mapbox.api.directions.v5.DirectionsAdapterFactory; +import com.mapbox.api.directions.v5.DirectionsCriteria; + +/** + * Class containing information about notification details specific to + * {@link Notification#type()} and {@link Notification#subtype()}. + */ +@AutoValue +public abstract class NotificationDetails extends DirectionsJsonObject { + + /** + * Create a new instance of this class by using the {@link Builder} class. + * + * @return this classes {@link Builder} for creating a new instance + */ + public static Builder builder() { + return new AutoValue_NotificationDetails.Builder(); + } + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is the requested value which was violated. + * + * @return requested value + */ + @SerializedName("requested_value") + @Nullable + public abstract String requestedValue(); + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is the actual value associated with the property of the road + * (as opposed to {@link NotificationDetails#requestedValue()}). + * + * @return actual value + */ + @SerializedName("actual_value") + @Nullable + public abstract String actualValue(); + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is unit of measure associated with + * {@link NotificationDetails#requestedValue()} and {@link NotificationDetails#actualValue()}. + * + * @return unit + */ + @Nullable + public abstract String unit(); + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is the message of the notification. + * + * @return message + */ + @Nullable + public abstract String message(); + + /** + * Convert the current {@link NotificationDetails} to its builder holding the currently assigned + * values. This allows you to modify a single property and then rebuild the object resulting in + * an updated and modified {@link NotificationDetails}. + * + * @return a {@link Builder} with the same values set to match the ones defined + * in this {@link Notification} + */ + public abstract Builder toBuilder(); + + /** + * Gson type adapter for parsing Gson to this class. + * + * @param gson the built {@link Gson} object + * @return the type adapter for this class + */ + public static TypeAdapter typeAdapter(Gson gson) { + return new AutoValue_NotificationDetails.GsonTypeAdapter(gson); + } + + /** + * Create a new instance of this class by passing in a formatted valid JSON String. + * + * @param json a formatted valid JSON string defining a NotificationDetails + * @return a new instance of this class defined by the values passed inside this static factory + * method + */ + public static NotificationDetails fromJson(String json) { + GsonBuilder gson = new GsonBuilder(); + gson.registerTypeAdapterFactory(DirectionsAdapterFactory.create()); + return gson.create().fromJson(json, NotificationDetails.class); + } + + /** + * This builder can be used to set the values describing the {@link NotificationDetails}. + */ + @AutoValue.Builder + public abstract static class Builder extends DirectionsJsonObject.Builder { + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is the requested value which was violated. + * + * @param requestedValue requested value + * @return this builder for chaining options together + */ + @SerializedName("requested_value") + @NonNull + public abstract Builder requestedValue(@Nullable String requestedValue); + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is the actual value associated with the property of the road + * (as opposed to {@link NotificationDetails#requestedValue()}). + * + * @param actualValue actual value + * @return this builder for chaining options together + */ + @SerializedName("actual_value") + @NonNull + public abstract Builder actualValue(@Nullable String actualValue); + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is unit of measure associated with + * {@link NotificationDetails#requestedValue()} and {@link NotificationDetails#actualValue()}. + * + * @param unit unit + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder unit(@Nullable String unit); + + /** + * If {@link Notification#type()} is {@link DirectionsCriteria#NOTIFICATION_TYPE_VIOLATION} + * and {@link Notification#subtype()} is one of: + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_HEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WIDTH}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_MAX_WEIGHT}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_UNPAVED}, + * {@link DirectionsCriteria#NOTIFICATION_SUBTYPE_POINT_EXCLUSION}, + * it is the message of the notification. + * + * @param message message + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder message(@Nullable String message); + + /** + * Build a new {@link NotificationDetails} object. + * + * @return a new {@link NotificationDetails} using the provided values in this builder + */ + @NonNull + public abstract NotificationDetails build(); + } +} diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteLeg.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteLeg.java index bd38c6b7c..bb424f4e3 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteLeg.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteLeg.java @@ -124,6 +124,14 @@ public static Builder builder() { @Nullable public abstract List closures(); + /** + * A list of notifications describing which requested parameters were violated (if any) and how. + * + * @return a list of {@link Notification}. + */ + @Nullable + public abstract List notifications(); + /** * Convert the current {@link RouteLeg} to its builder holding the currently assigned * values. This allows you to modify a single property and then rebuild the object resulting in @@ -272,6 +280,15 @@ public abstract static class Builder extends DirectionsJsonObject.Builder closures); + /** + * A list of notifications describing which requested parameters were violated (if any) and how. + * + * @param notifications a list of {@link Notification} + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder notifications(@Nullable List notifications); + /** * Build a new {@link RouteLeg} object. * diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java index d5ed873ee..efbe24687 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java @@ -1017,6 +1017,18 @@ public List paymentMethodsList() { @Nullable public abstract Boolean intersectionLinkBridge(); + /** + * Which notifications the response should contain (see {@link RouteLeg#notifications()}). + * For possible values see + * {@link com.mapbox.api.directions.v5.DirectionsCriteria.NotificationsFlowCriteria}. + * If null is passed, {@link DirectionsCriteria#NOTIFICATION_FLOW_ALL} value will be used. + * + * @return string representing `notifications` value. + */ + @Nullable + @DirectionsCriteria.NotificationsFlowCriteria + public abstract String notifications(); + /** * Gson type adapter for parsing Gson to this class. * @@ -1154,6 +1166,7 @@ public URL toUrl(@NonNull String accessToken) { appendQueryParameter(sb, "waypoints_per_route", waypointsPerRoute()); appendQueryParameter(sb, "metadata", metadata()); appendQueryParameter(sb, "payment_methods", paymentMethods()); + appendQueryParameter(sb, "notifications", notifications()); appendQueryParameter( sb, "suppress_voice_instruction_local_names", @@ -2311,6 +2324,20 @@ public abstract Builder intersectionLinkBridge( @Nullable Boolean intersectionLinkBridge ); + /** + * Which notifications the response should contain (see {@link RouteLeg#notifications()}). + * For possible values see + * {@link com.mapbox.api.directions.v5.DirectionsCriteria.NotificationsFlowCriteria}. + * If null is passed, {@link DirectionsCriteria#NOTIFICATION_FLOW_ALL} value will be used. + * + * @param notifications string representing `notifications` value. + * @return this builder + */ + @NonNull + public abstract Builder notifications( + @Nullable @DirectionsCriteria.NotificationsFlowCriteria String notifications + ); + /** * Use this method to add request parameters, * which are not present in the model yet but are supported on the Directions API, diff --git a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/NotificationDetailsTest.java b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/NotificationDetailsTest.java new file mode 100644 index 000000000..dbbcc2aa5 --- /dev/null +++ b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/NotificationDetailsTest.java @@ -0,0 +1,98 @@ +package com.mapbox.api.directions.v5.models; + +import com.google.gson.JsonPrimitive; +import com.mapbox.core.TestUtils; +import org.junit.Test; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class NotificationDetailsTest extends TestUtils { + + @Test + public void sanity() { + NotificationDetails details = NotificationDetails.builder().build(); + + assertNotNull(details); + } + + @Test + public void serializationDefaultObject() throws Exception { + NotificationDetails details = NotificationDetails.builder().build(); + + byte[] serialized = TestUtils.serialize(details); + assertEquals(details, deserialize(serialized, NotificationDetails.class)); + } + + @Test + public void serializationFilledObject() throws Exception { + NotificationDetails details = NotificationDetails.builder() + .message("some message") + .unit("meter") + .actualValue("111") + .requestedValue("99") + .unrecognizedJsonProperties(Collections.singletonMap("key1", new JsonPrimitive("value1"))) + .build(); + + byte[] serialized = TestUtils.serialize(details); + assertEquals(details, deserialize(serialized, NotificationDetails.class)); + } + + @Test + public void toFromJsonDefaultObject() { + NotificationDetails details = NotificationDetails.builder().build(); + + String serialized = details.toJson(); + assertEquals(details, NotificationDetails.fromJson(serialized)); + } + + @Test + public void toFromJsonFilledObject() { + NotificationDetails details = NotificationDetails.builder() + .message("some message") + .unit("meter") + .actualValue("111") + .requestedValue("99") + .unrecognizedJsonProperties(Collections.singletonMap("key1", new JsonPrimitive("value1"))) + .build(); + + String serialized = details.toJson(); + assertEquals(details, NotificationDetails.fromJson(serialized)); + } + + @Test + public void fromJsonDefaultObject() { + NotificationDetails expected = NotificationDetails.builder().build(); + + assertEquals(expected, NotificationDetails.fromJson("{}")); + } + + @Test + public void fromJsonFilledObject() { + NotificationDetails expected = NotificationDetails.builder() + .message("some message") + .unit("meter") + .actualValue("111") + .requestedValue("99") + .unrecognizedJsonProperties(Collections.singletonMap("key1", new JsonPrimitive("value1"))) + .build(); + String json = "{\"message\": \"some message\", \"unit\": \"meter\", " + + "\"actual_value\": \"111\", \"requested_value\": \"99\", " + + "\"key1\": \"value1\"}"; + + assertEquals(expected, NotificationDetails.fromJson(json)); + } + + @Test + public void fromJsonWithNumericValuesFilledObject() { + NotificationDetails expected = NotificationDetails.builder() + .actualValue("111") + .requestedValue("99") + .build(); + String json = "{\"actual_value\": 111, \"requested_value\": 99}"; + + assertEquals(expected, NotificationDetails.fromJson(json)); + } +} \ No newline at end of file diff --git a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/NotificationTest.java b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/NotificationTest.java new file mode 100644 index 000000000..acb169bd0 --- /dev/null +++ b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/NotificationTest.java @@ -0,0 +1,121 @@ +package com.mapbox.api.directions.v5.models; + +import com.google.gson.JsonPrimitive; +import com.mapbox.api.directions.v5.DirectionsCriteria; +import com.mapbox.core.TestUtils; +import org.junit.Test; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class NotificationTest extends TestUtils { + + @Test + public void sanity() { + Notification notification = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .build(); + + assertNotNull(notification); + } + + @Test + public void serializationDefaultObject() throws Exception { + Notification notification = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .build(); + + byte[] serialized = TestUtils.serialize(notification); + assertEquals(notification, deserialize(serialized, Notification.class)); + } + + @Test + public void serializationFilledObject() throws Exception { + Notification notification = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .subtype(DirectionsCriteria.NOTIFICATION_SUBTYPE_MAX_WIDTH) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .geometryIndexStart(100) + .geometryIndexEnd(123) + .details(NotificationDetails.builder().message("some message").build()) + .unrecognizedJsonProperties(Collections.singletonMap("key1", new JsonPrimitive("value1"))) + .build(); + + byte[] serialized = TestUtils.serialize(notification); + assertEquals(notification, deserialize(serialized, Notification.class)); + } + + @Test + public void toFromJsonDefaultObject() { + Notification notification = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .build(); + + String serialized = notification.toJson(); + assertEquals(notification, Notification.fromJson(serialized)); + } + + @Test + public void toFromJsonFilledObject() { + Notification notification = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .subtype(DirectionsCriteria.NOTIFICATION_SUBTYPE_MAX_WIDTH) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .geometryIndexStart(100) + .geometryIndexEnd(123) + .details(NotificationDetails.builder().message("some message").build()) + .unrecognizedJsonProperties(Collections.singletonMap("key1", new JsonPrimitive("value1"))) + .build(); + + String serialized = notification.toJson(); + assertEquals(notification, Notification.fromJson(serialized)); + } + + @Test + public void fromJsonDefaultObject() { + Notification expected = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .build(); + + assertEquals(expected, Notification.fromJson("{\"type\": \"violation\", \"refresh_type\": \"static\"}")); + } + + @Test + public void fromJsonFilledObject1() { + Notification expected = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .subtype(DirectionsCriteria.NOTIFICATION_SUBTYPE_MAX_WIDTH) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .geometryIndexStart(100) + .geometryIndexEnd(123) + .details(NotificationDetails.builder().message("some message").build()) + .unrecognizedJsonProperties(Collections.singletonMap("key1", new JsonPrimitive("value1"))) + .build(); + String json = "{\"type\": \"violation\", \"refresh_type\": \"static\", \"subtype\": \"maxWidth\", " + + "\"geometry_index_start\": 100, \"geometry_index_end\": 123, " + + "\"details\": {\"message\": \"some message\"}, \"key1\": \"value1\"}"; + + assertEquals(expected, Notification.fromJson(json)); + } + + @Test + public void fromJsonFilledObject2() { + Notification expected = Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_ALERT) + .subtype(DirectionsCriteria.NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_DYNAMIC) + .reason(DirectionsCriteria.NOTIFICATION_EV_STATION_OUT_OF_ORDER) + .chargingStationId("charging-station-1") + .build(); + String json = "{\"type\": \"alert\", \"refresh_type\": \"dynamic\", \"subtype\": \"stationUnavailable\", " + + "\"reason\": \"outOfOrder\", \"station_id\": \"charging-station-1\"}"; + + assertEquals(expected, Notification.fromJson(json)); + } +} \ No newline at end of file diff --git a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteLegTest.java b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteLegTest.java index 417bb3a72..23ac37bb5 100644 --- a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteLegTest.java +++ b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteLegTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import com.mapbox.api.directions.v5.DirectionsCriteria; import com.mapbox.core.TestUtils; import org.junit.Test; @@ -85,6 +86,16 @@ public void testToFromJson1() { .congestion(congestionList) .build(); + List notifications = Arrays.asList( + Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .subtype(DirectionsCriteria.NOTIFICATION_SUBTYPE_MAX_HEIGHT) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .geometryIndexStart(123) + .geometryIndexEnd(145) + .build() + ); + RouteLeg routeLeg = RouteLeg.builder() .annotation(annotation) .distance(53.4) @@ -93,6 +104,7 @@ public void testToFromJson1() { .incidents(incidents) .closures(closures) .summary("") + .notifications(notifications) .build(); String jsonString = routeLeg.toJson(); @@ -109,7 +121,8 @@ public void testFromJson() { + "\"summary\": \"route summary\"," + "\"admins\": [{ \"iso_3166_1_alpha3\": \"USA\", \"iso_3166_1\": \"US\" }]," + "\"incidents\": [{ \"id\": \"15985415522454461962\" }]," - + "\"closures\": [{ \"geometry_index_start\": 1,\"geometry_index_end\": 4}]}"; + + "\"closures\": [{ \"geometry_index_start\": 1,\"geometry_index_end\": 4}]," + + "\"notifications\": [{ \"geometry_index_start\": 123,\"geometry_index_end\": 145, \"type\": \"violation\", \"refresh_type\": \"dynamic\", \"subtype\": \"maxHeight\"}]}"; List admins = new ArrayList<>(); admins.add(Admin.builder().countryCode("US").countryCodeAlpha3("USA").build()); @@ -119,6 +132,16 @@ public void testFromJson() { List closures = new ArrayList<>(); closures.add(Closure.builder().geometryIndexStart(1).geometryIndexEnd(4).build()); + List notifications = Arrays.asList( + Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .subtype(DirectionsCriteria.NOTIFICATION_SUBTYPE_MAX_HEIGHT) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_DYNAMIC) + .geometryIndexStart(123) + .geometryIndexEnd(145) + .build() + ); + RouteLeg routeLeg = RouteLeg.builder() .distance(53.4) .duration(14.3) @@ -126,6 +149,7 @@ public void testFromJson() { .admins(admins) .incidents(incidents) .closures(closures) + .notifications(notifications) .build(); RouteLeg routeLegFromJson = RouteLeg.fromJson(routeLegJsonString); diff --git a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java index 0ba4676dd..4b677ec09 100644 --- a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java +++ b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java @@ -78,6 +78,7 @@ public class RouteOptionsTest extends TestUtils { "&waypoints_per_route=true" + "&metadata=true" + "&payment_methods=general" + + "¬ifications=none" + "&suppress_voice_instruction_local_names=true" + "&intersection_link_form_of_way=true" + "&intersection_link_geometry=motorway%2Ctrunk%2Cprimary" + @@ -403,6 +404,13 @@ public void suppressVoiceInstructionLocalNamesIsValid_fromJson() { assertEquals(true, options.suppressVoiceInstructionLocalNames()); } + @Test + public void notificationsIsValid_fromJson() { + RouteOptions options = RouteOptions.fromJson(optionsJson); + + assertEquals(DirectionsCriteria.NOTIFICATION_FLOW_NONE, options.notifications()); + } + @Test public void waypointsPerRouteAreValid_fromJson() { RouteOptions routeOptions = RouteOptions.fromJson(optionsJson); @@ -454,6 +462,13 @@ public void defaultSuppressVoiceInstructionLocalNames() { assertNull(options.suppressVoiceInstructionLocalNames()); } + @Test + public void defaultNotifications() { + RouteOptions options = defaultRouteOptions(); + + assertNull(options.notifications()); + } + @Test public void defaultWaypointsPerRoute() { RouteOptions options = defaultRouteOptions(); @@ -1221,6 +1236,7 @@ private RouteOptions routeOptions() { .intersectionLinkAccess(true) .intersectionLinkElevated(true) .intersectionLinkBridge(true) + .notifications(DirectionsCriteria.NOTIFICATION_FLOW_NONE) .build(); } @@ -1335,6 +1351,7 @@ private RouteOptions routeOptionsList() { .intersectionLinkElevated(true) .intersectionLinkBridge(true) .intersectionLinkGeometry(Arrays.asList("motorway", "trunk", "primary")) + .notifications(DirectionsCriteria.NOTIFICATION_FLOW_NONE) .build(); } } diff --git a/services-directions-models/src/test/resources/route_options_v5.json b/services-directions-models/src/test/resources/route_options_v5.json index 6e3db6b60..71b8fc3e2 100644 --- a/services-directions-models/src/test/resources/route_options_v5.json +++ b/services-directions-models/src/test/resources/route_options_v5.json @@ -44,5 +44,6 @@ "intersection_link_geometry": "motorway,trunk,primary", "intersection_link_access": true, "intersection_link_elevated": true, - "intersection_link_bridge": true + "intersection_link_bridge": true, + "notifications": "none" } diff --git a/services-directions-refresh-models/src/main/java/com/mapbox/api/directionsrefresh/v1/models/RouteLegRefresh.java b/services-directions-refresh-models/src/main/java/com/mapbox/api/directionsrefresh/v1/models/RouteLegRefresh.java index 711dc3f02..21774d531 100644 --- a/services-directions-refresh-models/src/main/java/com/mapbox/api/directionsrefresh/v1/models/RouteLegRefresh.java +++ b/services-directions-refresh-models/src/main/java/com/mapbox/api/directionsrefresh/v1/models/RouteLegRefresh.java @@ -11,6 +11,7 @@ import com.mapbox.api.directions.v5.models.DirectionsWaypoint; import com.mapbox.api.directions.v5.models.Incident; import com.mapbox.api.directions.v5.models.LegAnnotation; +import com.mapbox.api.directions.v5.models.Notification; import com.mapbox.api.directionsrefresh.v1.DirectionsRefreshAdapterFactory; import java.util.List; @@ -57,6 +58,15 @@ public static Builder builder() { @Nullable public abstract List closures(); + + /** + * A list of notifications that occur on this leg. + * + * @return a list of {@link Notification} + */ + @Nullable + public abstract List notifications(); + /** * Convert the current {@link RouteLegRefresh} to its builder holding the currently assigned * values. This allows you to modify a single property and then rebuild the object resulting in @@ -127,6 +137,15 @@ public abstract static class Builder extends DirectionsRefreshJsonObject.Builder @NonNull public abstract Builder closures(@Nullable List closures); + /** + * A list of notifications that occur on this leg. + * + * @param notifications a list of {@link Notification} + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder notifications(@Nullable List notifications); + /** * Build a new {@link RouteLegRefresh} object. * diff --git a/services-directions-refresh-models/src/test/java/com.mapbox.api.directionsrefresh.v1.models/RouteLegRefreshTest.java b/services-directions-refresh-models/src/test/java/com.mapbox.api.directionsrefresh.v1.models/RouteLegRefreshTest.java index a7a630f09..b225ba8ea 100644 --- a/services-directions-refresh-models/src/test/java/com.mapbox.api.directionsrefresh.v1.models/RouteLegRefreshTest.java +++ b/services-directions-refresh-models/src/test/java/com.mapbox.api.directionsrefresh.v1.models/RouteLegRefreshTest.java @@ -1,5 +1,6 @@ package com.mapbox.api.directionsrefresh.v1.models; +import com.mapbox.api.directions.v5.models.Notification; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -47,6 +48,16 @@ public void sanity() { .build() ) ) + .notifications( + Arrays.asList( + Notification.builder() + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .geometryIndexStart(1) + .geometryIndexEnd(2) + .build() + ) + ) .build(); } @@ -131,6 +142,23 @@ public void fromJson() { .build() ); + List notifications = Arrays.asList( + Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_VIOLATION) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_STATIC) + .geometryIndexStart(1) + .geometryIndex(2) + .geometryIndexEnd(3) + .build(), + Notification.builder() + .type(DirectionsCriteria.NOTIFICATION_TYPE_ALERT) + .subtype(DirectionsCriteria.NOTIFICATION_SUBTYPE_EV_STATION_UNAVAILABLE) + .refreshType(DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_DYNAMIC) + .reason(DirectionsCriteria.NOTIFICATION_EV_STATION_OUT_OF_ORDER) + .chargingStationId("charging-station-1") + .build() + ); + RouteLegRefresh routeLegRefresh = RouteLegRefresh.builder() .annotation( LegAnnotation.builder() @@ -144,6 +172,7 @@ public void fromJson() { ) .incidents(incidents) .closures(closures) + .notifications(notifications) .build(); String json = routeLegRefresh.toJson(); @@ -152,6 +181,7 @@ public void fromJson() { assertNotNull(routeLegRefresh.annotation()); assertNotNull(routeLegRefresh.incidents()); assertNotNull(routeLegRefresh.closures()); + assertNotNull(routeLegRefresh.notifications()); assertEquals(routeLegRefresh, fromJson); } diff --git a/services-directions/src/main/java/com/mapbox/api/directions/v5/DirectionsService.java b/services-directions/src/main/java/com/mapbox/api/directions/v5/DirectionsService.java index d54dae5e2..2005f5216 100644 --- a/services-directions/src/main/java/com/mapbox/api/directions/v5/DirectionsService.java +++ b/services-directions/src/main/java/com/mapbox/api/directions/v5/DirectionsService.java @@ -59,6 +59,7 @@ interface DirectionsService { * @param computeTollCost {@link RouteOptions#computeTollCost()} * @param waypointsPerRoute {@link RouteOptions#waypointsPerRoute()} * @param metadata {@link RouteOptions#metadata()} + * @param notifications {@link RouteOptions#notifications()} * @return the {@link DirectionsResponse} in a Call wrapper */ @GET("directions/v5/{user}/{profile}/{coordinates}") @@ -104,7 +105,8 @@ Call getCall( @Query("waypoints_per_route") Boolean waypointsPerRoute, @Query("metadata") Boolean metadata, @Query("payment_methods") String paymentMethods, - @Query("suppress_voice_instruction_local_names") Boolean suppressVoiceInstructionLocalNames + @Query("suppress_voice_instruction_local_names") Boolean suppressVoiceInstructionLocalNames, + @Query("notifications") String notifications ); /** @@ -149,6 +151,7 @@ Call getCall( * @param computeTollCost {@link RouteOptions#computeTollCost()} * @param waypointsPerRoute {@link RouteOptions#waypointsPerRoute()} * @param metadata {@link RouteOptions#metadata()} + * @param notifications {@link RouteOptions#notifications()} * @return the {@link DirectionsResponse} in a Call wrapper */ @FormUrlEncoded @@ -195,6 +198,7 @@ Call postCall( @Field("waypoints_per_route") Boolean waypointsPerRoute, @Field("metadata") Boolean metadata, @Field("payment_methods") String paymentMethods, - @Field("suppress_voice_instruction_local_names") Boolean suppressVoiceInstructionLocalNames + @Field("suppress_voice_instruction_local_names") Boolean suppressVoiceInstructionLocalNames, + @Field("notifications") String notifications ); } diff --git a/services-directions/src/main/java/com/mapbox/api/directions/v5/MapboxDirections.java b/services-directions/src/main/java/com/mapbox/api/directions/v5/MapboxDirections.java index c674ebb5e..128eb05d8 100644 --- a/services-directions/src/main/java/com/mapbox/api/directions/v5/MapboxDirections.java +++ b/services-directions/src/main/java/com/mapbox/api/directions/v5/MapboxDirections.java @@ -113,7 +113,8 @@ private Call get() { routeOptions().waypointsPerRoute(), routeOptions().metadata(), routeOptions().paymentMethods(), - routeOptions().suppressVoiceInstructionLocalNames() + routeOptions().suppressVoiceInstructionLocalNames(), + routeOptions().notifications() ); } @@ -160,7 +161,8 @@ private Call post() { routeOptions().waypointsPerRoute(), routeOptions().metadata(), routeOptions().paymentMethods(), - routeOptions().suppressVoiceInstructionLocalNames() + routeOptions().suppressVoiceInstructionLocalNames(), + routeOptions().notifications() ); } diff --git a/services-directions/src/test/java/com/mapbox/api/directions/v5/MapboxDirectionsTest.java b/services-directions/src/test/java/com/mapbox/api/directions/v5/MapboxDirectionsTest.java index 3038f057b..a71b0ab51 100644 --- a/services-directions/src/test/java/com/mapbox/api/directions/v5/MapboxDirectionsTest.java +++ b/services-directions/src/test/java/com/mapbox/api/directions/v5/MapboxDirectionsTest.java @@ -360,6 +360,16 @@ public void include_doesGetFormattedInUrlCorrectly() throws Exception { assertTrue(directions.cloneCall().request().url().toString().contains("include=hot")); } + @Test + public void notifications_doesGetFormattedInUrlCorrectly() throws Exception { + MapboxDirections directions = MapboxDirections.builder() + .accessToken("token") + .routeOptions(routeOptions) + .build(); + + assertTrue(directions.cloneCall().request().url().toString().contains("notifications=none")); + } + @Test public void callFactoryNonNull() throws IOException { MapboxDirections client = MapboxDirections.builder() diff --git a/services-directions/src/test/resources/route_options_v5.json b/services-directions/src/test/resources/route_options_v5.json index 16c4afe78..cfe03f5ae 100644 --- a/services-directions/src/test/resources/route_options_v5.json +++ b/services-directions/src/test/resources/route_options_v5.json @@ -39,5 +39,6 @@ "waypoints_per_route": true, "metadata": true, "payment_methods": "general,etcx", - "suppress_voice_instruction_local_names": true + "suppress_voice_instruction_local_names": true, + "notifications": "none" } \ No newline at end of file