• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.car.CarApiUtil;
19 import android.car.CarLibLog;
20 import android.car.CarManagerBase;
21 import android.car.CarNotConnectedException;
22 import android.graphics.Bitmap;
23 import android.os.Handler;
24 import android.os.Handler.Callback;
25 import android.os.IBinder;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.RemoteException;
29 import android.util.Log;
30 
31 import java.lang.ref.WeakReference;
32 
33 /**
34  * API for providing navigation status for instrument cluster.
35  * @hide
36  */
37 public class CarNavigationManager implements CarManagerBase {
38 
39     /**
40      * Listener navigation related events.
41      * Callbacks are called in the Looper context.
42      */
43     public interface CarNavigationListener {
44         /** Instrument Cluster started in navigation mode */
onInstrumentClusterStart(CarNavigationInstrumentCluster instrumentCluster)45         void onInstrumentClusterStart(CarNavigationInstrumentCluster instrumentCluster);
46         /** Instrument cluster ended */
onInstrumentClusterStop()47         void onInstrumentClusterStop();
48     }
49 
50     /** Navigation status */
51     public static final int STATUS_UNAVAILABLE = 0;
52     public static final int STATUS_ACTIVE = 1;
53     public static final int STATUS_INACTIVE = 2;
54     /** Turn Types */
55     public static final int TURN_UNKNOWN = 0;
56     public static final int TURN_DEPART = 1;
57     public static final int TURN_NAME_CHANGE = 2;
58     public static final int TURN_SLIGHT_TURN = 3;
59     public static final int TURN_TURN = 4;
60     public static final int TURN_SHARP_TURN = 5;
61     public static final int TURN_U_TURN = 6;
62     public static final int TURN_ON_RAMP = 7;
63     public static final int TURN_OFF_RAMP = 8;
64     public static final int TURN_FORK = 9;
65     public static final int TURN_MERGE = 10;
66     public static final int TURN_ROUNDABOUT_ENTER = 11;
67     public static final int TURN_ROUNDABOUT_EXIT = 12;
68     public static final int TURN_ROUNDABOUT_ENTER_AND_EXIT = 13;
69     public static final int TURN_STRAIGHT = 14;
70     public static final int TURN_FERRY_BOAT = 16;
71     public static final int TURN_FERRY_TRAIN = 17;
72     public static final int TURN_DESTINATION = 19;
73     /** Turn Side */
74     public static final int TURN_SIDE_LEFT = 1;
75     public static final int TURN_SIDE_RIGHT = 2;
76     public static final int TURN_SIDE_UNSPECIFIED = 3;
77 
78     private static final int START = 1;
79     private static final int STOP = 2;
80 
81     private static final String TAG = CarLibLog.TAG_NAV;
82 
83     private final ICarNavigation mService;
84     private ICarNavigationEventListenerImpl mICarNavigationEventListenerImpl;
85     private CarNavigationListener mCarNavigationListener;
86     private CarNavigationInstrumentCluster mInstrumentCluster;
87     private final Handler mHandler;
88     private final Callback mHandlerCallback = new Callback() {
89         @Override
90         public boolean handleMessage(Message msg) {
91             Log.d(TAG, "handleMessage, listener: " + mCarNavigationListener + ", msg.what: " +
92                     msg.what);
93             if (mCarNavigationListener != null) {
94                 switch (msg.what) {
95                     case START:
96                         Log.d(TAG, "mCarNavigationListener.onInstrumentClusterStart()");
97                         mCarNavigationListener.onInstrumentClusterStart(mInstrumentCluster);
98                         break;
99                     case STOP:
100                         mCarNavigationListener.onInstrumentClusterStop();
101                         break;
102                 }
103             }
104             return true;
105         }
106     };
107 
108     /**
109      * Only for CarServiceLoader
110      * @hide
111      */
CarNavigationManager(IBinder service, Looper looper)112     public CarNavigationManager(IBinder service, Looper looper) {
113         mHandler = new Handler(looper, mHandlerCallback);
114         mService = ICarNavigation.Stub.asInterface(service);
115     }
116 
117     /**
118      * @param status new instrument cluster navigation status.
119      * @return true if successful.
120      * @throws CarNotConnectedException
121      */
sendNavigationStatus(int status)122     public boolean sendNavigationStatus(int status) throws CarNotConnectedException {
123         try {
124             mService.sendNavigationStatus(status);
125         } catch (IllegalStateException e) {
126             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
127         } catch (RemoteException e) {
128             handleCarServiceRemoteExceptionAndThrow(e);
129             return false;
130         }
131         return true;
132     }
133 
134     /**
135      * Sends a Navigation Next Step event to the car.
136      * <p>
137      * Note: For an example of a roundabout: if a roundabout has 4 exits, spaced evenly, then the
138      * first exit will have turnNumber=1, turnAngle=90; the second will have turnNumber=2,
139      * turnAngle=180; the third will have turnNumber=3, turnAngle=270.  turnNumber and turnAngle are
140      * counted in the direction of travel around the roundabout (clockwise for roads where the car
141      * drives on the left-hand side of the road, such as Australia; anti-clockwise for roads where
142      * the car drives on the right, such as the USA).
143      *
144      * @param event event type ({@link #TURN_TURN}, {@link #TURN_U_TURN},
145      *        {@link #TURN_ROUNDABOUT_ENTER_AND_EXIT}, etc).
146      * @param road Name of the road
147      * @param turnAngle turn angle in degrees between the roundabout entry and exit (0..359).  Only
148      *        used for event type {@link #TURN_ROUNDABOUT_ENTER_AND_EXIT}.  -1 if unused.
149      * @param turnNumber turn number, counting around from the roundabout entry to the exit.  Only
150      *        used for event type {@link #TURN_ROUNDABOUT_ENTER_AND_EXIT}.  -1 if unused.
151      * @param image image to be shown in the instrument cluster.  Null if instrument
152      *        cluster type doesn't support images.
153      * @param turnSide turn side ({@link #TURN_SIDE_LEFT}, {@link #TURN_SIDE_RIGHT} or
154      *        {@link #TURN_SIDE_UNSPECIFIED}).
155      * @return true if successful.
156      * @throws CarNotConnectedException
157      *
158      */
sendNavigationTurnEvent(int event, String road, int turnAngle, int turnNumber, Bitmap image, int turnSide)159     public boolean sendNavigationTurnEvent(int event, String road, int turnAngle, int turnNumber,
160             Bitmap image, int turnSide) throws CarNotConnectedException {
161         try {
162             mService.sendNavigationTurnEvent(event, road, turnAngle, turnNumber, image, turnSide);
163         } catch (IllegalStateException e) {
164             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
165         } catch (RemoteException e) {
166             handleCarServiceRemoteExceptionAndThrow(e);
167             return false;
168         }
169         return true;
170     }
171 
172     /**
173      * Sends a Navigation Next Step Distance event to the car.
174      *
175      * @param distanceMeters Distance to next event in meters.
176      * @param timeSeconds Time to next event in seconds.
177      * @return true if successful.
178      * @throws CarNotConnectedException
179      */
sendNavigationTurnDistanceEvent(int distanceMeters, int timeSeconds)180     public boolean sendNavigationTurnDistanceEvent(int distanceMeters, int timeSeconds)
181             throws CarNotConnectedException {
182         try {
183             mService.sendNavigationTurnDistanceEvent(distanceMeters, timeSeconds);
184         } catch (IllegalStateException e) {
185             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
186         } catch (RemoteException e) {
187             handleCarServiceRemoteExceptionAndThrow(e);
188             return false;
189         }
190         return true;
191     }
192 
isInstrumentClusterSupported()193     public boolean isInstrumentClusterSupported() throws CarNotConnectedException {
194         try {
195             return mService.isInstrumentClusterSupported();
196         } catch (IllegalStateException e) {
197             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
198         } catch (RemoteException e) {
199             handleCarServiceRemoteExceptionAndThrow(e);
200         }
201         return false;
202     }
203 
204     @Override
onCarDisconnected()205     public void onCarDisconnected() {
206         Log.d(TAG, "onCarDisconnected");
207         unregisterListener();
208     }
209 
210     /**
211      * @param listener {@link CarNavigationListener} to be registered, replacing any existing
212      *        listeners.
213      * @throws CarNotConnectedException
214      */
registerListener(CarNavigationListener listener)215     public void registerListener(CarNavigationListener listener)
216             throws CarNotConnectedException {
217         mCarNavigationListener = listener;
218         if (mICarNavigationEventListenerImpl == null) {
219             mICarNavigationEventListenerImpl =
220                     new ICarNavigationEventListenerImpl(this);
221             try {
222                 mService.registerEventListener(mICarNavigationEventListenerImpl);
223             } catch (IllegalStateException e) {
224                 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
225             } catch (RemoteException e) {
226                 handleCarServiceRemoteExceptionAndThrow(e);
227             }
228         }
229     }
230 
231     /**
232      * Unregisters {@link CarNavigationListener}.
233      */
unregisterListener()234     public void unregisterListener() {
235         try {
236             mService.unregisterEventListener(mICarNavigationEventListenerImpl);
237         } catch (IllegalStateException e) {
238             // ignore
239         } catch (RemoteException e) {
240             // do not throw exception as this can happen during tearing down.
241             handleCarServiceRemoteException(e);
242         }
243         mCarNavigationListener = null;
244     }
245 
handleCarServiceRemoteExceptionAndThrow(RemoteException e)246     private void handleCarServiceRemoteExceptionAndThrow(RemoteException e)
247             throws CarNotConnectedException {
248         handleCarServiceRemoteException(e);
249         throw new CarNotConnectedException();
250     }
251 
handleCarServiceRemoteException(RemoteException e)252     private void handleCarServiceRemoteException(RemoteException e) {
253         Log.w(TAG, "RemoteException from car service:" + e.getMessage());
254         // nothing to do for now
255     }
256 
handleOnStart(CarNavigationInstrumentCluster instrumentCluster)257     private void handleOnStart(CarNavigationInstrumentCluster instrumentCluster) {
258         Log.d(TAG, "onStart(" + instrumentCluster + ")");
259         mInstrumentCluster = new CarNavigationInstrumentCluster(instrumentCluster);
260         mHandler.sendMessage(mHandler.obtainMessage(START));
261     }
262 
handleOnStop()263     private void handleOnStop() {
264         mHandler.sendMessage(mHandler.obtainMessage(STOP));
265     }
266 
267     private static class ICarNavigationEventListenerImpl extends ICarNavigationEventListener.Stub {
268         private final WeakReference<CarNavigationManager> mManager;
269 
ICarNavigationEventListenerImpl(CarNavigationManager manager)270         public ICarNavigationEventListenerImpl(CarNavigationManager manager) {
271             mManager = new WeakReference<>(manager);
272         }
273 
274         @Override
onInstrumentClusterStart(CarNavigationInstrumentCluster instrumentClusterInfo)275         public void onInstrumentClusterStart(CarNavigationInstrumentCluster instrumentClusterInfo) {
276             CarNavigationManager manager = mManager.get();
277             if (manager != null) {
278                 manager.handleOnStart(instrumentClusterInfo);
279             }
280         }
281 
282         @Override
onInstrumentClusterStop()283         public void onInstrumentClusterStop() {
284             CarNavigationManager manager = mManager.get();
285             if (manager != null) {
286                 manager.handleOnStop();
287             }
288         }
289     }
290 }
291