blob: d86e51316c2d49318add350649be49c13923535c [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.car.app.navigation.model;
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static java.util.Objects.requireNonNull;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.model.CarIcon;
import androidx.car.app.model.constraints.CarIconConstraints;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/** Information about a maneuver that the driver will be required to perform. */
// TODO(b/154671667): Update when host(s) updates or a scheme for auto sync is established.
@CarProtocol
public final class Maneuver {
/**
* Possible maneuver types.
*
* @hide
*/
@IntDef({
TYPE_UNKNOWN,
TYPE_DEPART,
TYPE_NAME_CHANGE,
TYPE_KEEP_LEFT,
TYPE_KEEP_RIGHT,
TYPE_TURN_SLIGHT_LEFT,
TYPE_TURN_SLIGHT_RIGHT,
TYPE_TURN_NORMAL_LEFT,
TYPE_TURN_NORMAL_RIGHT,
TYPE_TURN_SHARP_LEFT,
TYPE_TURN_SHARP_RIGHT,
TYPE_U_TURN_LEFT,
TYPE_U_TURN_RIGHT,
TYPE_ON_RAMP_SLIGHT_LEFT,
TYPE_ON_RAMP_SLIGHT_RIGHT,
TYPE_ON_RAMP_NORMAL_LEFT,
TYPE_ON_RAMP_NORMAL_RIGHT,
TYPE_ON_RAMP_SHARP_LEFT,
TYPE_ON_RAMP_SHARP_RIGHT,
TYPE_ON_RAMP_U_TURN_LEFT,
TYPE_ON_RAMP_U_TURN_RIGHT,
TYPE_OFF_RAMP_SLIGHT_LEFT,
TYPE_OFF_RAMP_SLIGHT_RIGHT,
TYPE_OFF_RAMP_NORMAL_LEFT,
TYPE_OFF_RAMP_NORMAL_RIGHT,
TYPE_FORK_LEFT,
TYPE_FORK_RIGHT,
TYPE_MERGE_LEFT,
TYPE_MERGE_RIGHT,
TYPE_MERGE_SIDE_UNSPECIFIED,
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW,
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE,
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW,
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE,
TYPE_STRAIGHT,
TYPE_FERRY_BOAT,
TYPE_FERRY_TRAIN,
TYPE_DESTINATION,
TYPE_DESTINATION_STRAIGHT,
TYPE_DESTINATION_LEFT,
TYPE_DESTINATION_RIGHT,
TYPE_ROUNDABOUT_ENTER_CW,
TYPE_ROUNDABOUT_EXIT_CW,
TYPE_ROUNDABOUT_ENTER_CCW,
TYPE_ROUNDABOUT_EXIT_CCW,
TYPE_FERRY_BOAT_LEFT,
TYPE_FERRY_BOAT_RIGHT,
TYPE_FERRY_TRAIN_LEFT,
TYPE_FERRY_TRAIN_RIGHT,
})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(LIBRARY)
public @interface Type {
}
/**
* Maneuver type is unknown, no maneuver information should be displayed.
*
* <p>This type may be interpreted differently depending on the consumer. In some
* cases the previous maneuver will continue to be shown while in others no maneuver will be
* shown at all.
*/
@Type
public static final int TYPE_UNKNOWN = 0;
/**
* Starting point of the navigation.
*
* <p>For example, "Start driving on Main St."
*/
@Type
public static final int TYPE_DEPART = 1;
/**
* No turn, but the street name changes.
*
* <p>For example, "Continue on Main St."
*/
@Type
public static final int TYPE_NAME_CHANGE = 2;
/**
* No turn, from 0 (included) to 10 (excluded) degrees.
*
* <p>This is used in contrast to {@link #TYPE_STRAIGHT} for disambiguating cases where there is
* more than one option to go into the same general direction.
*/
@Type
public static final int TYPE_KEEP_LEFT = 3;
/**
* No turn, from 0 (included) to 10 (excluded) degrees.
*
* <p>This is used in contrast to {@link #TYPE_STRAIGHT} for disambiguating cases where there is
* more than one option to go into the same general direction.
*/
@Type
public static final int TYPE_KEEP_RIGHT = 4;
/** Slight left turn at an intersection, from 10 (included) to 45 (excluded) degrees. */
@Type
public static final int TYPE_TURN_SLIGHT_LEFT = 5;
/** Slight right turn at an intersection, from 10 (included) to 45 (excluded) degrees. */
@Type
public static final int TYPE_TURN_SLIGHT_RIGHT = 6;
/** Regular left turn at an intersection, from 45 (included) to 135 (excluded) degrees. */
@Type
public static final int TYPE_TURN_NORMAL_LEFT = 7;
/** Regular right turn at an intersection, from 45 (included) to 135 (excluded) degrees. */
@Type
public static final int TYPE_TURN_NORMAL_RIGHT = 8;
/** Sharp left turn at an intersection, from 135 (included) to 175 (excluded) degrees. */
@Type
public static final int TYPE_TURN_SHARP_LEFT = 9;
/** Sharp right turn at an intersection, from 135 (included) to 175 (excluded) degrees. */
@Type
public static final int TYPE_TURN_SHARP_RIGHT = 10;
/**
* Left turn onto the opposite side of the same street, from 175 (included) to 180 (included)
* degrees.
*/
@Type
public static final int TYPE_U_TURN_LEFT = 11;
/**
* A right turn onto the opposite side of the same street, from 175 (included) to 180 (included)
* degrees.
*/
@Type
public static final int TYPE_U_TURN_RIGHT = 12;
/**
* Slight left turn to enter a turnpike or freeway, from 10 (included) to 45 (excluded) degrees.
*/
@Type
public static final int TYPE_ON_RAMP_SLIGHT_LEFT = 13;
/**
* Slight right turn to enter a turnpike or freeway, from 10 (included) to 45 (excluded)
* degrees.
*/
@Type
public static final int TYPE_ON_RAMP_SLIGHT_RIGHT = 14;
/**
* Regular left turn to enter a turnpike or freeway, from 45 (included) to 135 (excluded)
* degrees.
*/
@Type
public static final int TYPE_ON_RAMP_NORMAL_LEFT = 15;
/**
* Regular right turn to enter a turnpike or freeway, from 45 (included) to 135 (excluded)
* degrees.
*/
@Type
public static final int TYPE_ON_RAMP_NORMAL_RIGHT = 16;
/**
* Sharp left turn to enter a turnpike or freeway, from 135 (included) to 175 (excluded)
* degrees.
*/
@Type
public static final int TYPE_ON_RAMP_SHARP_LEFT = 17;
/**
* Sharp right turn to enter a turnpike or freeway, from 135 (included) to 175 (excluded)
* degrees.
*/
@Type
public static final int TYPE_ON_RAMP_SHARP_RIGHT = 18;
/**
* Left turn onto the opposite side of the same street to enter a turnpike or freeway, from 175
* (included) to 180 (included).
*/
@Type
public static final int TYPE_ON_RAMP_U_TURN_LEFT = 19;
/**
* Right turn onto the opposite side of the same street to enter a turnpike or freeway, from 175
* (included) to 180 (included).
*/
@Type
public static final int TYPE_ON_RAMP_U_TURN_RIGHT = 20;
/** A left turn to exit a turnpike or freeway, from 10 (included) to 45 (excluded) degrees. */
@Type
public static final int TYPE_OFF_RAMP_SLIGHT_LEFT = 21;
/** A right turn to exit a turnpike or freeway, from 10 (included) to 45 (excluded) degrees. */
@Type
public static final int TYPE_OFF_RAMP_SLIGHT_RIGHT = 22;
/** A left turn to exit a turnpike or freeway, from 45 (included) to 135 (excluded) degrees. */
@Type
public static final int TYPE_OFF_RAMP_NORMAL_LEFT = 23;
/** A left right to exit a turnpike or freeway, from 45 (included) to 135 (excluded) degrees. */
@Type
public static final int TYPE_OFF_RAMP_NORMAL_RIGHT = 24;
/**
* Keep to the left as the road diverges.
*
* <p>For example, this is used to indicate "Keep left at the fork".
*/
@Type
public static final int TYPE_FORK_LEFT = 25;
/**
* Keep to the right as the road diverges.
*
* <p>For example, this is used to indicate "Keep right at the fork".
*/
@Type
public static final int TYPE_FORK_RIGHT = 26;
/**
* Current road joins another on the left.
*
* <p>For example, this is used to indicate "Merge left onto Main St.".
*/
@Type
public static final int TYPE_MERGE_LEFT = 27;
/**
* Current road joins another on the right.
*
* <p>For example, this is used to indicate "Merge left onto Main St.".
*/
@Type
public static final int TYPE_MERGE_RIGHT = 28;
/**
* Current road joins another without direction specified.
*
* <p>For example, this is used to indicate "Merge onto Main St.".
*/
@Type
public static final int TYPE_MERGE_SIDE_UNSPECIFIED = 29;
/**
* Enter a clockwise roundabout and take the Nth exit.
*
* <p>The exit number must be passed when created the maneuver.
*
* <p>For example, this is used to indicate "At the roundabout, take the Nth exit".
*/
@Type
public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW = 32;
/**
* Enter a clockwise roundabout and take the Nth exit after angle A degrees.
*
* <p>The exit number and angle must be passed when creating the maneuver.
*
* <p>For example, this is used to indicate "At the roundabout, take the Nth exit".
*/
@Type
public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE = 33;
/**
* Enter a counter-clockwise roundabout and take the Nth exit.
*
* <p>The exit number must be passed when created the maneuver.
*
* <p>For example, this is used to indicate "At the roundabout, take the Nth exit".
*/
@Type
public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW = 34;
/**
* Enter a counter-clockwise roundabout and take the Nth exit after angle A degrees.
*
* <p>The exit number and angle must be passed when creating the maneuver.
*
* <p>For example, this is used to indicate "At the roundabout, take a sharp right at the Nth
* exit".
*/
@Type
public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE = 35;
/** Driver should steer straight. */
@Type
public static final int TYPE_STRAIGHT = 36;
/**
* Drive towards a boat ferry for vehicles, where the entrance is straight ahead or in an
* unknown direction.
*
* <p>For example, this is used to indicate "Take the ferry".
*/
@Type
public static final int TYPE_FERRY_BOAT = 37;
/**
* Drive towards a train ferry for vehicles (e.g. "Take the train"), where the entrance is
* straight ahead or in an unknown direction.
*/
@Type
public static final int TYPE_FERRY_TRAIN = 38;
/** Arrival at a destination. */
@Type
public static final int TYPE_DESTINATION = 39;
/** Arrival to a destination located straight ahead. */
@Type
public static final int TYPE_DESTINATION_STRAIGHT = 40;
/** Arrival to a destination located to the left side of the road. */
@Type
public static final int TYPE_DESTINATION_LEFT = 41;
/** Arrival to a destination located to the right side of the road. */
@Type
public static final int TYPE_DESTINATION_RIGHT = 42;
/**
* Entrance to a clockwise roundabout on which the current road ends.
*
* <p>For example, this is used to indicate "Enter the roundabout".
*/
@Type
public static final int TYPE_ROUNDABOUT_ENTER_CW = 43;
/**
* Used when leaving a clockwise roundabout when the step starts in it.
*
* <p>For example, this is used to indicate "Exit the roundabout".
*/
@Type
public static final int TYPE_ROUNDABOUT_EXIT_CW = 44;
/**
* Entrance to a counter-clockwise roundabout on which the current road ends.
*
* <p>For example, this is used to indicate "Enter the roundabout".
*/
@Type
public static final int TYPE_ROUNDABOUT_ENTER_CCW = 45;
/**
* Used when leaving a counter-clockwise roundabout when the step starts in it.
*
* <p>For example, this is used to indicate "Exit the roundabout".
*/
@Type
public static final int TYPE_ROUNDABOUT_EXIT_CCW = 46;
/**
* Drive towards a boat ferry for vehicles, where the entrance is to the left.
*
* <p>For example, this is used to indicate "Take the ferry".
*/
@Type
public static final int TYPE_FERRY_BOAT_LEFT = 47;
/**
* Drive towards a boat ferry for vehicles, where the entrance is to the right.
*
* <p>For example, this is used to indicate "Take the ferry".
*/
@Type
public static final int TYPE_FERRY_BOAT_RIGHT = 48;
/**
* Drive towards a train ferry for vehicles (e.g. "Take the train"), where the entrance is to
* the
* left.
*/
@Type
public static final int TYPE_FERRY_TRAIN_LEFT = 49;
/**
* Drive towards a train ferry for vehicles (e.g. "Take the train"), where the entrance is to
* the
* right.
*/
@Type
public static final int TYPE_FERRY_TRAIN_RIGHT = 50;
@Keep
@Type
private final int mType;
@Keep
private final int mRoundaboutExitNumber;
@Keep
private final int mRoundaboutExitAngle;
@Keep
@Nullable
private final CarIcon mIcon;
/**
* Returns the maneuver type.
*
* <p>Required to be set at all times.
*/
@Type
public int getType() {
return mType;
}
/**
* Returns the roundabout exit number, starting from 1 to designate the first exit after joining
* the roundabout, and increasing in circulation order. Only relevant if the type is any
* variation of {@code TYPE_ROUNDABOUT_ENTER_AND_EXIT_*}.
*
* <p>For example, if the driver is joining a counter-clockwise roundabout with 4 exits, then
* the exit to the right would be exit #1, the one straight ahead would be exit #2, the one
* to the left would be exit #3 and the one used by the driver to join the roundabout would
* be exit #4.
*
* <p>Required when the type is a roundabout.
*/
public int getRoundaboutExitNumber() {
return mRoundaboutExitNumber;
}
/**
* Returns the roundabout exit angle in degrees to designate the amount of distance to travel
* around the roundabout. Only relevant if the type is {@link
* #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE} or {@link
* #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE}.
*
* <p>For example, if the drive is joining a counter-clockwise roundabout with equally spaced
* exits then the exit to the right would be at 90 degrees, the one straight ahead would be
* at 180 degrees, the one to the left would at 270 degrees and the one used by the driver to
* join the roundabout would be at 360 degrees.
*
* <p>The angle can also be set for irregular roundabouts. For example a roundabout with three
* exits at 90, 270 and 360 degrees could also have the desired exit angle specified.
*
* <p>Required with the type is a roundabout with an angle.
*/
public int getRoundaboutExitAngle() {
return mRoundaboutExitAngle;
}
/**
* Returns the icon for the maneuver.
*
* <p>Optional field that when not set may be shown in the target display by a generic image
* representing the specific maneuver.
*/
@Nullable
public CarIcon getIcon() {
return mIcon;
}
@Override
@NonNull
public String toString() {
return "[type: "
+ mType
+ ", exit #: "
+ mRoundaboutExitNumber
+ ", exit angle: "
+ mRoundaboutExitAngle
+ ", icon: "
+ mIcon
+ "]";
}
@Override
public int hashCode() {
return Objects.hash(mType, mRoundaboutExitNumber, mRoundaboutExitAngle, mIcon);
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Maneuver)) {
return false;
}
Maneuver otherManeuver = (Maneuver) other;
return mType == otherManeuver.mType
&& mRoundaboutExitNumber == otherManeuver.mRoundaboutExitNumber
&& mRoundaboutExitAngle == otherManeuver.mRoundaboutExitAngle
&& Objects.equals(mIcon, otherManeuver.mIcon);
}
Maneuver(@Type int type, int roundaboutExitNumber, int roundaboutExitAngle,
@Nullable CarIcon icon) {
mType = type;
mRoundaboutExitNumber = roundaboutExitNumber;
mRoundaboutExitAngle = roundaboutExitAngle;
CarIconConstraints.DEFAULT.validateOrThrow(icon);
mIcon = icon;
}
/** Constructs an empty instance, used by serialization code. */
private Maneuver() {
mType = TYPE_UNKNOWN;
mRoundaboutExitNumber = 0;
mRoundaboutExitAngle = 0;
mIcon = null;
}
static boolean isValidType(@Type int type) {
return (type >= TYPE_UNKNOWN && type <= TYPE_FERRY_TRAIN_RIGHT);
}
static boolean isValidTypeWithExitNumber(@Type int type) {
return (type == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW
|| type == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW
|| type == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE
|| type == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE);
}
static boolean isValidTypeWithExitAngle(@Type int type) {
return (type == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE
|| type == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE);
}
/** A builder of {@link Maneuver}. */
public static final class Builder {
@Type
private final int mType;
private boolean mIsRoundaboutExitNumberSet;
private int mRoundaboutExitNumber;
private boolean mIsRoundaboutExitAngleSet;
private int mRoundaboutExitAngle;
@Nullable
private CarIcon mIcon;
/**
* Constructs a new instance of a {@link Builder}.
*
* <p>The type should be chosen to reflect the closest semantic meaning of the maneuver.
* In some cases, an exact type match is not possible, but choosing a similar or slightly
* more general type is preferred. Using {@link #TYPE_UNKNOWN} is allowed, but some head
* units will not display any information in that case.
*
* @param type one of the {@code TYPE_*} static constants defined in this class
* @throws IllegalArgumentException if {@code type} is not a valid maneuver type
*/
public Builder(@Type int type) {
if (!isValidType(type)) {
throw new IllegalArgumentException("Maneuver must have a valid type");
}
mType = type;
}
/**
* Sets an image representing the maneuver.
*
* <h4>Icon Sizing Guidance</h4>
*
* To minimize scaling artifacts across a wide range of car screens, apps should provide
* icons targeting a 128 x 128 dp bounding box. If the icon exceeds this maximum size in
* either one of the dimensions, it will be scaled down to be centered inside the
* bounding box while preserving its aspect ratio.
*
* <p>See {@link CarIcon} for more details related to providing icon and image resources
* that work with different car screen pixel densities.
*
* @throws NullPointerException if {@code icon} is {@code null}
*/
@NonNull
public Builder setIcon(@NonNull CarIcon icon) {
mIcon = requireNonNull(icon);
return this;
}
/**
* Sets an exit number for roundabout maneuvers.
*
* <p>Use for when {@code type} is {@link #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW}, {@link
* #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW},
* {@link #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE} or
* {@link #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE}. The {@code
* roundaboutExitNumber} starts from 1 to designate the first exit after joining the
* roundabout, and increases in circulation order.
*
* <p>For example, if the driver is joining a counter-clockwise roundabout with 4 exits,
* then the exit to the right would be exit #1, the one straight ahead would be exit #2,
* the one to the left would be exit #3 and the one used by the driver to join the
* roundabout would be exit #4.
*
* @throws IllegalArgumentException if {@code type} does not include a exit number, or
* if {@code roundaboutExitNumber} is not greater than
* zero
*/
@NonNull
public Builder setRoundaboutExitNumber(@IntRange(from = 1) int roundaboutExitNumber) {
if (!isValidTypeWithExitNumber(mType)) {
throw new IllegalArgumentException(
"Maneuver does not include roundaboutExitNumber");
}
if (roundaboutExitNumber < 1) {
throw new IllegalArgumentException("Maneuver must include a valid exit number");
}
mIsRoundaboutExitNumberSet = true;
mRoundaboutExitNumber = roundaboutExitNumber;
return this;
}
/**
* Sets an exit angle for roundabout maneuvers.
*
* <p>Use for when {@code type} is {@link #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE} or
* {@link #TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE}. The {@code roundaboutExitAngle}
* represents the degrees traveled in circulation from the entrance to the exit.
*
* <p>For example, in a 4 exit example, if all the exits are equally spaced then exit 1
* would be at 90 degrees, exit 2 at 180, exit 3 at 270 and exit 4 at 360. However if the
* exits are irregular then a different angle could be provided.
*
* @throws IllegalArgumentException if {@code type} does not include a exit angle or if
* {@code roundaboutExitAngle} is not greater than zero
* and less than or equal to 360 degrees
*/
@NonNull
public Builder setRoundaboutExitAngle(
@IntRange(from = 1, to = 360) int roundaboutExitAngle) {
if (!isValidTypeWithExitAngle(mType)) {
throw new IllegalArgumentException("Maneuver does not include roundaboutExitAngle");
}
if (roundaboutExitAngle < 1 || roundaboutExitAngle > 360) {
throw new IllegalArgumentException("Maneuver must include a valid exit angle");
}
mIsRoundaboutExitAngleSet = true;
mRoundaboutExitAngle = roundaboutExitAngle;
return this;
}
/**
* Constructs the {@link Maneuver} defined by this builder.
*
* @throws IllegalArgumentException if {@code type} includes an exit number and one has
* not been set, or if it includes an exit angle and one
* has not been set
*/
@NonNull
public Maneuver build() {
if (isValidTypeWithExitNumber(mType) && !mIsRoundaboutExitNumberSet) {
throw new IllegalArgumentException("Maneuver missing roundaboutExitNumber");
}
if (isValidTypeWithExitAngle(mType) && !mIsRoundaboutExitAngleSet) {
throw new IllegalArgumentException("Maneuver missing roundaboutExitAngle");
}
return new Maneuver(mType, mRoundaboutExitNumber, mRoundaboutExitAngle, mIcon);
}
}
}