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