1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.car.navigation; 17 18 import android.annotation.IntDef; 19 import android.car.CarApiUtil; 20 import android.car.CarLibLog; 21 import android.car.CarManagerBase; 22 import android.car.CarNotConnectedException; 23 import android.car.cluster.renderer.IInstrumentClusterNavigation; 24 import android.graphics.Bitmap; 25 import android.os.Bundle; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.util.Log; 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 32 /** 33 * API for providing navigation status for instrument cluster. 34 * @hide 35 */ 36 public final class CarNavigationStatusManager implements CarManagerBase { 37 38 /** Navigation status */ 39 public static final int STATUS_UNAVAILABLE = 0; 40 public static final int STATUS_ACTIVE = 1; 41 public static final int STATUS_INACTIVE = 2; 42 43 /** @hide */ 44 @IntDef({ 45 STATUS_UNAVAILABLE, 46 STATUS_ACTIVE, 47 STATUS_INACTIVE 48 }) 49 @Retention(RetentionPolicy.SOURCE) 50 public @interface Status {} 51 52 /* Turn Types */ 53 /** Turn is of an unknown type.*/ 54 public static final int TURN_UNKNOWN = 0; 55 /** Starting point of the navigation. */ 56 public static final int TURN_DEPART = 1; 57 /** No turn, but the street name changes. */ 58 public static final int TURN_NAME_CHANGE = 2; 59 /** Slight turn. */ 60 public static final int TURN_SLIGHT_TURN = 3; 61 /** Regular turn. */ 62 public static final int TURN_TURN = 4; 63 /** Sharp turn. */ 64 public static final int TURN_SHARP_TURN = 5; 65 /** U-turn. */ 66 public static final int TURN_U_TURN = 6; 67 /** On ramp. */ 68 public static final int TURN_ON_RAMP = 7; 69 /** Off ramp. */ 70 public static final int TURN_OFF_RAMP = 8; 71 /** Road forks (diverges). */ 72 public static final int TURN_FORK = 9; 73 /** Road merges. */ 74 public static final int TURN_MERGE = 10; 75 /** Roundabout entrance on which the route ends. Instruction says "Enter roundabout". */ 76 public static final int TURN_ROUNDABOUT_ENTER = 11; 77 /** Roundabout exit. */ 78 public static final int TURN_ROUNDABOUT_EXIT = 12; 79 /** 80 * Roundabout entrance and exit. For example, "At the roundabout, take Nth exit." Be sure to 81 * specify the "turnNumber" parameter when using this type. 82 */ 83 public static final int TURN_ROUNDABOUT_ENTER_AND_EXIT = 13; 84 /** Potentially confusing intersection where the user should steer straight. */ 85 public static final int TURN_STRAIGHT = 14; 86 /** You're on a boat! */ 87 public static final int TURN_FERRY_BOAT = 16; 88 /** Train ferries for vehicles. */ 89 public static final int TURN_FERRY_TRAIN = 17; 90 /** You have arrived. */ 91 public static final int TURN_DESTINATION = 19; 92 93 /** @hide */ 94 @IntDef({ 95 TURN_UNKNOWN, 96 TURN_DEPART, 97 TURN_NAME_CHANGE, 98 TURN_SLIGHT_TURN, 99 TURN_TURN, 100 TURN_SHARP_TURN, 101 TURN_U_TURN, 102 TURN_ON_RAMP, 103 TURN_OFF_RAMP, 104 TURN_FORK, 105 TURN_MERGE, 106 TURN_ROUNDABOUT_ENTER, 107 TURN_ROUNDABOUT_EXIT, 108 TURN_ROUNDABOUT_ENTER_AND_EXIT, 109 TURN_STRAIGHT, 110 TURN_FERRY_BOAT, 111 TURN_FERRY_TRAIN, 112 TURN_DESTINATION 113 }) 114 @Retention(RetentionPolicy.SOURCE) 115 public @interface TurnEvent {} 116 117 /** 118 * Event type that holds information about next maneuver. 119 * @hide 120 */ 121 public static final int EVENT_TYPE_NEXT_MANEUVER_INFO = 1; 122 /** 123 * Event type that holds information regarding distance/time to the next maneuver. 124 * @hide 125 */ 126 public static final int EVENT_TYPE_NEXT_MANEUVER_COUNTDOWN = 2; 127 /** 128 * All custom (vendor-specific) event types should be equal or greater than this constant. 129 * @hide 130 */ 131 public static final int EVENT_TYPE_VENDOR_FIRST = 1024; 132 133 /* Turn Side */ 134 /** Turn is on the left side of the vehicle. */ 135 public static final int TURN_SIDE_LEFT = 1; 136 /** Turn is on the right side of the vehicle. */ 137 public static final int TURN_SIDE_RIGHT = 2; 138 /** Turn side is unspecified. */ 139 public static final int TURN_SIDE_UNSPECIFIED = 3; 140 141 /** @hide */ 142 @IntDef({ 143 TURN_SIDE_LEFT, 144 TURN_SIDE_RIGHT, 145 TURN_SIDE_UNSPECIFIED 146 }) 147 public @interface TurnSide {} 148 149 private static final int START = 1; 150 private static final int STOP = 2; 151 152 /** 153 * Distance units for use in {@link #sendNavigationTurnDistanceEvent(int, int, int, int)}. 154 */ 155 /** Distance is specified in meters. */ 156 public static final int DISTANCE_METERS = 1; 157 /** Distance is specified in kilometers. */ 158 public static final int DISTANCE_KILOMETERS = 2; 159 /** Distance is specified in miles. */ 160 public static final int DISTANCE_MILES = 3; 161 /** Distance is specified in feet. */ 162 public static final int DISTANCE_FEET = 4; 163 /** Distance is specified in yards. */ 164 public static final int DISTANCE_YARDS = 5; 165 166 /** @hide */ 167 @IntDef({ 168 DISTANCE_METERS, 169 DISTANCE_KILOMETERS, 170 DISTANCE_MILES, 171 DISTANCE_FEET, 172 DISTANCE_YARDS 173 }) 174 public @interface DistanceUnit {} 175 176 private static final String TAG = CarLibLog.TAG_NAV; 177 178 private final IInstrumentClusterNavigation mService; 179 180 181 /** 182 * Only for CarServiceLoader 183 * @hide 184 */ 185 public CarNavigationStatusManager(IBinder service) { 186 mService = IInstrumentClusterNavigation.Stub.asInterface(service); 187 } 188 189 /** 190 * @param status new instrument cluster navigation status. 191 * @throws CarNotConnectedException if the connection to the car service has been lost. 192 */ 193 public void sendNavigationStatus(@Status int status) throws CarNotConnectedException { 194 try { 195 if (status == STATUS_ACTIVE) { 196 mService.onStartNavigation(); 197 } else { 198 mService.onStopNavigation(); 199 } 200 } catch (IllegalStateException e) { 201 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 202 } catch (RemoteException e) { 203 handleCarServiceRemoteExceptionAndThrow(e); 204 } 205 } 206 207 /** 208 * Sends a Navigation Next Step event to the car. 209 * <p> 210 * Note: For an example of a roundabout: if a roundabout has 4 exits, spaced evenly, then the 211 * first exit will have turnNumber=1, turnAngle=90; the second will have turnNumber=2, 212 * turnAngle=180; the third will have turnNumber=3, turnAngle=270. turnNumber and turnAngle are 213 * counted in the direction of travel around the roundabout (clockwise for roads where the car 214 * drives on the left-hand side of the road, such as Australia; anti-clockwise for roads where 215 * the car drives on the right, such as the USA). 216 * 217 * @param turnEvent turn event like ({@link #TURN_TURN}, {@link #TURN_U_TURN}, 218 * {@link #TURN_ROUNDABOUT_ENTER_AND_EXIT}, etc). 219 * @param eventName Name of the turn event like road name to turn. For example "Charleston road" 220 * in "Turn right to Charleston road" 221 * @param turnAngle turn angle in degrees between the roundabout entry and exit (0..359). Only 222 * used for event type {@link #TURN_ROUNDABOUT_ENTER_AND_EXIT}. -1 if unused. 223 * @param turnNumber turn number, counting around from the roundabout entry to the exit. Only 224 * used for event type {@link #TURN_ROUNDABOUT_ENTER_AND_EXIT}. -1 if unused. 225 * @param image image to be shown in the instrument cluster. Null if instrument 226 * cluster type doesn't support images. 227 * @param turnSide turn side ({@link #TURN_SIDE_LEFT}, {@link #TURN_SIDE_RIGHT} or 228 * {@link #TURN_SIDE_UNSPECIFIED}). 229 * @throws CarNotConnectedException if the connection to the car service has been lost. 230 * 231 * @deprecated Use {@link #sendEvent(int, Bundle)} instead. 232 */ 233 public void sendNavigationTurnEvent(@TurnEvent int turnEvent, CharSequence eventName, 234 int turnAngle, int turnNumber, Bitmap image, @TurnSide int turnSide) 235 throws CarNotConnectedException { 236 try { 237 mService.onNextManeuverChanged(turnEvent, eventName, turnAngle, turnNumber, image, 238 turnSide); 239 } catch (IllegalStateException e) { 240 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 241 } catch (RemoteException e) { 242 handleCarServiceRemoteExceptionAndThrow(e); 243 } 244 } 245 246 /** 247 * Sends a Navigation Next Step Distance event to the car. 248 * 249 * @param distanceMeters Distance to next event in meters. 250 * @param timeSeconds Time to next event in seconds. 251 * @param displayDistanceMillis Distance to the next event. This is exactly the same distance 252 * that navigation app is displaying. Use it when you want to display distance, it has 253 * appropriate rounding function and units are in sync with navigation app. This parameter is 254 * in {@code displayDistanceUnit * 1000}. 255 * @param displayDistanceUnit units for {@param displayDistanceMillis} param. 256 * See {@link DistanceUnit} for acceptable values. 257 * @throws CarNotConnectedException if the connection to the car service has been lost. 258 * 259 * @deprecated Use {@link #sendEvent(int, Bundle)} instead. 260 */ 261 public void sendNavigationTurnDistanceEvent(int distanceMeters, int timeSeconds, 262 int displayDistanceMillis, @DistanceUnit int displayDistanceUnit) 263 throws CarNotConnectedException { 264 try { 265 mService.onNextManeuverDistanceChanged(distanceMeters, timeSeconds, 266 displayDistanceMillis, displayDistanceUnit); 267 } catch (IllegalStateException e) { 268 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 269 } catch (RemoteException e) { 270 handleCarServiceRemoteExceptionAndThrow(e); 271 } 272 } 273 274 /** 275 * Sends events from navigation app to instrument cluster. 276 * 277 * @param eventType event type 278 * @param bundle object that holds data about the event 279 * @throws CarNotConnectedException if the connection to the car service has been lost. 280 * 281 * @see #EVENT_TYPE_NEXT_MANEUVER_INFO 282 * @see #EVENT_TYPE_NEXT_MANEUVER_COUNTDOWN 283 * 284 * @hide 285 */ 286 public void sendEvent(int eventType, Bundle bundle) throws CarNotConnectedException { 287 try { 288 mService.onEvent(eventType, bundle); 289 } catch (IllegalStateException e) { 290 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 291 } catch (RemoteException e) { 292 handleCarServiceRemoteExceptionAndThrow(e); 293 } 294 } 295 296 @Override 297 public void onCarDisconnected() { 298 Log.d(TAG, "onCarDisconnected"); 299 } 300 301 /** Returns navigation features of instrument cluster */ 302 public CarNavigationInstrumentCluster getInstrumentClusterInfo() 303 throws CarNotConnectedException { 304 try { 305 return mService.getInstrumentClusterInfo(); 306 } catch (RemoteException e) { 307 handleCarServiceRemoteExceptionAndThrow(e); 308 } 309 return null; 310 } 311 312 private void handleCarServiceRemoteExceptionAndThrow(RemoteException e) 313 throws CarNotConnectedException { 314 handleCarServiceRemoteException(e); 315 throw new CarNotConnectedException(); 316 } 317 318 private void handleCarServiceRemoteException(RemoteException e) { 319 Log.w(TAG, "RemoteException from car service:" + e.getMessage()); 320 // nothing to do for now 321 } 322 } 323