• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 
17 package android.car.drivingstate;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.car.Car;
23 import android.car.CarManagerBase;
24 import android.car.CarNotConnectedException;
25 import android.car.drivingstate.ICarDrivingState;
26 import android.content.Context;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.os.RemoteException;
32 import android.util.Log;
33 import java.lang.ref.WeakReference;
34 
35 /**
36  * API to register and get driving state related information in a car.
37  * @hide
38  */
39 @SystemApi
40 public final class CarDrivingStateManager implements CarManagerBase {
41     private static final String TAG = "CarDrivingStateMgr";
42     private static final boolean DBG = false;
43     private static final boolean VDBG = false;
44     private static final int MSG_HANDLE_DRIVING_STATE_CHANGE = 0;
45 
46     private final Context mContext;
47     private final ICarDrivingState mDrivingService;
48     private final EventCallbackHandler mEventCallbackHandler;
49     private CarDrivingStateEventListener mDrvStateEventListener;
50     private CarDrivingStateChangeListenerToService mListenerToService;
51 
52 
53     /** @hide */
CarDrivingStateManager(IBinder service, Context context, Handler handler)54     public CarDrivingStateManager(IBinder service, Context context, Handler handler) {
55         mContext = context;
56         mDrivingService = ICarDrivingState.Stub.asInterface(service);
57         mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
58     }
59 
60     /** @hide */
61     @Override
onCarDisconnected()62     public synchronized void onCarDisconnected() {
63             mListenerToService = null;
64             mDrvStateEventListener = null;
65     }
66 
67     /**
68      * Listener Interface for clients to implement to get updated on driving state changes.
69      */
70     public interface CarDrivingStateEventListener {
71         /**
72          * Called when the car's driving state changes.
73          * @param event Car's driving state.
74          */
onDrivingStateChanged(CarDrivingStateEvent event)75         void onDrivingStateChanged(CarDrivingStateEvent event);
76     }
77 
78     /**
79      * Register a {@link CarDrivingStateEventListener} to listen for driving state changes.
80      *
81      * @param listener  {@link CarDrivingStateEventListener}
82      */
registerListener(@onNull CarDrivingStateEventListener listener)83     public synchronized void registerListener(@NonNull CarDrivingStateEventListener listener)
84             throws CarNotConnectedException, IllegalArgumentException {
85         if (listener == null) {
86             if (VDBG) {
87                 Log.v(TAG, "registerCarDrivingStateEventListener(): null listener");
88             }
89             throw new IllegalArgumentException("Listener is null");
90         }
91         // Check if the listener has been already registered for this event type
92         if (mDrvStateEventListener != null) {
93             if (DBG) {
94                 Log.d(TAG, "Listener already registered");
95             }
96             return;
97         }
98         mDrvStateEventListener = listener;
99         try {
100             if (mListenerToService == null) {
101                 mListenerToService = new CarDrivingStateChangeListenerToService(this);
102             }
103             // register to the Service for getting notified
104             mDrivingService.registerDrivingStateChangeListener(mListenerToService);
105         } catch (RemoteException e) {
106             Log.e(TAG, "Could not register a listener to Driving State Service " + e);
107             throw new CarNotConnectedException(e);
108         } catch (IllegalStateException e) {
109             Log.e(TAG, "Could not register a listener to Driving State Service " + e);
110             Car.checkCarNotConnectedExceptionFromCarService(e);
111         }
112     }
113 
114     /**
115      * Unregister the registered {@link CarDrivingStateEventListener} for the given driving event
116      * type.
117      */
unregisterListener()118     public synchronized void unregisterListener()
119             throws CarNotConnectedException {
120         if (mDrvStateEventListener == null) {
121             if (DBG) {
122                 Log.d(TAG, "Listener was not previously registered");
123             }
124             return;
125         }
126         try {
127             mDrivingService.unregisterDrivingStateChangeListener(mListenerToService);
128             mDrvStateEventListener = null;
129             mListenerToService = null;
130         } catch (RemoteException e) {
131             Log.e(TAG, "Could not unregister listener from Driving State Service " + e);
132             throw new CarNotConnectedException(e);
133         }
134     }
135 
136     /**
137      * Get the current value of the car's driving state.
138      *
139      * @return {@link CarDrivingStateEvent} corresponding to the given eventType
140      */
141     @Nullable
getCurrentCarDrivingState()142     public CarDrivingStateEvent getCurrentCarDrivingState()
143             throws CarNotConnectedException {
144         try {
145             return mDrivingService.getCurrentDrivingState();
146         } catch (RemoteException e) {
147             Log.e(TAG, "Could not get current driving state " + e);
148             throw new CarNotConnectedException(e);
149         }
150     }
151 
152     /**
153      * Class that implements the listener interface and gets called back from the
154      * {@link com.android.car.CarDrivingStateService} across the binder interface.
155      */
156     private static class CarDrivingStateChangeListenerToService extends
157             ICarDrivingStateChangeListener.Stub {
158         private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
159 
CarDrivingStateChangeListenerToService(CarDrivingStateManager manager)160         public CarDrivingStateChangeListenerToService(CarDrivingStateManager manager) {
161             mDrvStateMgr = new WeakReference<>(manager);
162         }
163 
164         @Override
onDrivingStateChanged(CarDrivingStateEvent event)165         public void onDrivingStateChanged(CarDrivingStateEvent event) {
166             CarDrivingStateManager manager = mDrvStateMgr.get();
167             if (manager != null) {
168                 manager.handleDrivingStateChanged(event);
169             }
170         }
171     }
172 
173     /**
174      * Gets the {@link CarDrivingStateEvent} from the service listener
175      * {@link CarDrivingStateChangeListenerToService} and dispatches it to a handler provided
176      * to the manager
177      *
178      * @param event  {@link CarDrivingStateEvent} that has been registered to listen on
179      */
handleDrivingStateChanged(CarDrivingStateEvent event)180     private void handleDrivingStateChanged(CarDrivingStateEvent event) {
181         // send a message to the handler
182         mEventCallbackHandler.sendMessage(
183                 mEventCallbackHandler.obtainMessage(MSG_HANDLE_DRIVING_STATE_CHANGE, event));
184 
185     }
186 
187     /**
188      * Callback Handler to handle dispatching the driving state changes to the corresponding
189      * listeners
190      */
191     private static final class EventCallbackHandler extends Handler {
192         private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
193 
EventCallbackHandler(CarDrivingStateManager manager, Looper looper)194         public EventCallbackHandler(CarDrivingStateManager manager, Looper looper) {
195             super(looper);
196             mDrvStateMgr = new WeakReference<>(manager);
197         }
198 
199         @Override
handleMessage(Message msg)200         public void handleMessage(Message msg) {
201             CarDrivingStateManager mgr = mDrvStateMgr.get();
202             if (mgr != null) {
203                 mgr.dispatchDrivingStateChangeToClient((CarDrivingStateEvent) msg.obj);
204             }
205         }
206 
207     }
208 
209     /**
210      * Checks for the listener to {@link CarDrivingStateEvent} and calls it back
211      * in the callback handler thread
212      *
213      * @param event  {@link CarDrivingStateEvent}
214      */
dispatchDrivingStateChangeToClient(CarDrivingStateEvent event)215     private void dispatchDrivingStateChangeToClient(CarDrivingStateEvent event) {
216         if (event == null) {
217             return;
218         }
219         CarDrivingStateEventListener listener;
220         synchronized (this) {
221             listener = mDrvStateEventListener;
222         }
223         if (listener != null) {
224             listener.onDrivingStateChanged(event);
225         }
226     }
227 
228 }
229