• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.occupantawareness;
18 
19 import android.annotation.NonNull;
20 import android.annotation.RequiresPermission;
21 import android.car.Car;
22 import android.car.CarManagerBase;
23 import android.car.annotation.AddedInOrBefore;
24 import android.car.annotation.RequiredFeature;
25 import android.car.occupantawareness.OccupantAwarenessDetection.VehicleOccupantRole;
26 import android.car.occupantawareness.SystemStatusEvent.DetectionTypeFlags;
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 
34 import com.android.internal.annotations.GuardedBy;
35 
36 import java.lang.ref.WeakReference;
37 
38 /**
39  * API exposing Occupant Awareness System data.
40  *
41  * <p>Supported detections include: presence detection, {@link GazeDetection} and {@link
42  * DriverMonitoringDetection}.
43  *
44  * @hide
45  */
46 @RequiredFeature(Car.OCCUPANT_AWARENESS_SERVICE)
47 public class OccupantAwarenessManager extends CarManagerBase {
48     private static final String TAG = "OAS.Manager";
49     private static final boolean DBG = false;
50 
51     private static final int MSG_HANDLE_SYSTEM_STATUS_CHANGE = 0;
52     private static final int MSG_HANDLE_DETECTION_EVENT = 1;
53 
54     private final android.car.occupantawareness.IOccupantAwarenessManager mOccupantAwarenessService;
55 
56     private final Object mLock = new Object();
57 
58     @GuardedBy("mLock")
59     private ChangeCallback mChangeCallback;
60 
61     private final EventCallbackHandler mEventCallbackHandler;
62 
63     @GuardedBy("mLock")
64     private ChangeListenerToService mListenerToService;
65 
66     /** @hide */
OccupantAwarenessManager(Car car, IBinder service)67     public OccupantAwarenessManager(Car car, IBinder service) {
68         super(car);
69         mOccupantAwarenessService =
70                 android.car.occupantawareness.IOccupantAwarenessManager.Stub.asInterface(service);
71 
72         mEventCallbackHandler = new EventCallbackHandler(this, getEventHandler().getLooper());
73     }
74 
75     /** @hide */
76     @Override
77     @AddedInOrBefore(majorVersion = 33)
onCarDisconnected()78     public void onCarDisconnected() {
79         synchronized (mLock) {
80             mChangeCallback = null;
81             mListenerToService = null;
82         }
83     }
84 
85     /**
86      * Gets the detection capabilities for a given {@link VehicleOccupantRole} in this vehicle.
87      *
88      * <p>There may be different detection capabilities for different {@link VehicleOccupantRole}.
89      * Each role should be queried independently.
90      *
91      * <p>Capabilities are static for a given vehicle configuration and need only be queried once
92      * per vehicle. Once capability is determined, clients should query system status via {@link
93      * SystemStatusEvent} to see if the subsystem is currently online and ready to serve.
94      *
95      * @param role {@link VehicleOccupantRole} to query for.
96      * @return {@link SystemStatusEvent.DetectionTypeFlags} indicating supported capabilities for
97      *     the role.
98      */
99     @RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
100     @AddedInOrBefore(majorVersion = 33)
getCapabilityForRole(@ehicleOccupantRole int role)101     public @DetectionTypeFlags int getCapabilityForRole(@VehicleOccupantRole int role) {
102         try {
103             return mOccupantAwarenessService.getCapabilityForRole(role);
104         } catch (RemoteException e) {
105             return handleRemoteExceptionFromCarService(e, 0);
106         }
107     }
108 
109     /**
110      * Callbacks for listening to changes to {@link SystemStatusEvent} and {@link
111      * OccupantAwarenessDetection}.
112      */
113     public abstract static class ChangeCallback {
114         /**
115          * Called when the system state changes changes.
116          *
117          * @param systemStatus The new system state as a {@link SystemStatusEvent}.
118          */
119         @AddedInOrBefore(majorVersion = 33)
onSystemStateChanged(@onNull SystemStatusEvent systemStatus)120         public abstract void onSystemStateChanged(@NonNull SystemStatusEvent systemStatus);
121 
122         /**
123          * Called when a detection event is generated.
124          *
125          * @param event The new detection state as a {@link OccupantAwarenessDetection}.
126          */
127         @AddedInOrBefore(majorVersion = 33)
onDetectionEvent(@onNull OccupantAwarenessDetection event)128         public abstract void onDetectionEvent(@NonNull OccupantAwarenessDetection event);
129     }
130 
131     /**
132      * Registers a {@link ChangeCallback} for listening for events.
133      *
134      * <p>If a listener has already been registered, it has to be unregistered before registering
135      * the new one.
136      *
137      * @param callback {@link ChangeCallback} to register.
138      * @throws IllegalStateException if an existing callback is already registered.
139      */
140     @RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
141     @AddedInOrBefore(majorVersion = 33)
registerChangeCallback(@onNull ChangeCallback callback)142     public void registerChangeCallback(@NonNull ChangeCallback callback) {
143         if (DBG) {
144             Log.d(TAG, "Registering change listener");
145         }
146 
147         synchronized (mLock) {
148             // Check if the listener has been already registered.
149             if (mChangeCallback != null) {
150                 throw new IllegalStateException(
151                         "Attempting to register a new listener when an existing listener has"
152                                 + " already been registered.");
153             }
154 
155             mChangeCallback = callback;
156 
157             try {
158                 if (mListenerToService == null) {
159                     mListenerToService = new ChangeListenerToService(this);
160                 }
161 
162                 mOccupantAwarenessService.registerEventListener(mListenerToService);
163             } catch (RemoteException e) {
164                 handleRemoteExceptionFromCarService(e);
165             }
166         }
167     }
168 
169     /** Unregisters a previously registered {@link ChangeCallback}. */
170     @RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
171     @AddedInOrBefore(majorVersion = 33)
unregisterChangeCallback()172     public void unregisterChangeCallback() {
173         if (DBG) {
174             Log.d(TAG, "Unregistering change listener");
175         }
176 
177         synchronized (mLock) {
178             if (mChangeCallback == null) {
179                 Log.e(TAG, "No listener exists to unregister.");
180                 return;
181             }
182             mChangeCallback = null;
183         }
184 
185         synchronized (mLock) {
186             try {
187                 mOccupantAwarenessService.unregisterEventListener(mListenerToService);
188             } catch (RemoteException e) {
189                 handleRemoteExceptionFromCarService(e);
190             }
191 
192             mListenerToService = null;
193         }
194     }
195 
196     /**
197      * Class that implements the listener interface and gets called back from the {@link
198      * com.android.car.IOccupantAwarenessEventCallback} across the binder interface.
199      */
200     private static class ChangeListenerToService extends IOccupantAwarenessEventCallback.Stub {
201         private final WeakReference<OccupantAwarenessManager> mOccupantAwarenessManager;
202 
ChangeListenerToService(OccupantAwarenessManager manager)203         ChangeListenerToService(OccupantAwarenessManager manager) {
204             mOccupantAwarenessManager = new WeakReference<>(manager);
205         }
206 
207         @Override
onStatusChanged(SystemStatusEvent systemStatus)208         public void onStatusChanged(SystemStatusEvent systemStatus) {
209             OccupantAwarenessManager manager = mOccupantAwarenessManager.get();
210             if (manager != null) {
211                 manager.handleSystemStatusChanged(systemStatus);
212             }
213         }
214 
215         @Override
onDetectionEvent(OccupantAwarenessDetection event)216         public void onDetectionEvent(OccupantAwarenessDetection event) {
217             OccupantAwarenessManager manager = mOccupantAwarenessManager.get();
218             if (manager != null) {
219                 manager.handleDetectionEvent(event);
220             }
221         }
222     }
223 
224     /**
225      * Gets the {@link SystemStatusEvent} from the service listener {@link
226      * SystemStateChangeListenerToService} and dispatches it to a handler provided to the manager.
227      *
228      * @param systemStatus {@link SystemStatusEvent} that has been registered to listen on
229      */
handleSystemStatusChanged(SystemStatusEvent systemStatus)230     private void handleSystemStatusChanged(SystemStatusEvent systemStatus) {
231         // Send a message via the handler.
232         mEventCallbackHandler.sendMessage(
233                 mEventCallbackHandler.obtainMessage(MSG_HANDLE_SYSTEM_STATUS_CHANGE, systemStatus));
234     }
235 
236     /**
237      * Checks for the listeners to list of {@link SystemStatusEvent} and calls them back in the
238      * callback handler thread.
239      *
240      * @param systemStatus {@link SystemStatusEvent}
241      */
dispatchSystemStatusToClient(SystemStatusEvent systemStatus)242     private void dispatchSystemStatusToClient(SystemStatusEvent systemStatus) {
243         if (systemStatus == null) {
244             return;
245         }
246 
247         synchronized (mLock) {
248             if (mChangeCallback != null) {
249                 mChangeCallback.onSystemStateChanged(systemStatus);
250             }
251         }
252     }
253 
254     /**
255      * Gets the {@link OccupantAwarenessDetection} from the service listener {@link
256      * DetectionEventListenerToService} and dispatches it to a handler provided to the manager.
257      *
258      * @param detectionEvent {@link OccupantAwarenessDetection} that has been registered to listen
259      *     on
260      */
handleDetectionEvent(OccupantAwarenessDetection detectionEvent)261     private void handleDetectionEvent(OccupantAwarenessDetection detectionEvent) {
262         // Send a message via the handler.
263         mEventCallbackHandler.sendMessage(
264                 mEventCallbackHandler.obtainMessage(MSG_HANDLE_DETECTION_EVENT, detectionEvent));
265     }
266 
267     /**
268      * Checks for the listeners to list of {@link
269      * android.car.occupantawareness.OccupantAwarenessDetection} and calls them back in the callback
270      * handler thread.
271      *
272      * @param detectionEvent {@link OccupantAwarenessDetection}
273      */
dispatchDetectionEventToClient(OccupantAwarenessDetection detectionEvent)274     private void dispatchDetectionEventToClient(OccupantAwarenessDetection detectionEvent) {
275         if (detectionEvent == null) {
276             return;
277         }
278 
279         ChangeCallback callback;
280 
281         synchronized (mLock) {
282             callback = mChangeCallback;
283         }
284 
285         if (callback != null) {
286 
287             callback.onDetectionEvent(detectionEvent);
288         }
289     }
290 
291     /** Callback handler to dispatch system status changes to the corresponding listeners. */
292     private static final class EventCallbackHandler extends Handler {
293         private final WeakReference<OccupantAwarenessManager> mOccupantAwarenessManager;
294 
EventCallbackHandler(OccupantAwarenessManager manager, Looper looper)295         EventCallbackHandler(OccupantAwarenessManager manager, Looper looper) {
296             super(looper);
297             mOccupantAwarenessManager = new WeakReference<>(manager);
298         }
299 
300         @Override
handleMessage(Message msg)301         public void handleMessage(Message msg) {
302             OccupantAwarenessManager mgr = mOccupantAwarenessManager.get();
303             if (mgr != null) {
304 
305                 switch (msg.what) {
306                     case MSG_HANDLE_SYSTEM_STATUS_CHANGE:
307                         mgr.dispatchSystemStatusToClient((SystemStatusEvent) msg.obj);
308                         break;
309 
310                     case MSG_HANDLE_DETECTION_EVENT:
311                         mgr.dispatchDetectionEventToClient((OccupantAwarenessDetection) msg.obj);
312                         break;
313 
314                     default:
315                         throw new RuntimeException("Unknown message " + msg.what);
316                 }
317             }
318         }
319     }
320 }
321