• 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.experimental;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.car.Car;
23 import android.car.CarManagerBase;
24 import android.car.annotation.RequiredFeature;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.os.RemoteException;
30 import android.util.Log;
31 
32 import java.lang.ref.WeakReference;
33 import java.util.concurrent.CopyOnWriteArrayList;
34 
35 /**
36  * Experimental APIs that allow clients to consume information about a driver's current distraction
37  * level.
38  *
39  * @hide
40  */
41 @RequiredFeature(ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE)
42 public final class CarDriverDistractionManager extends CarManagerBase {
43 
44     private static final String TAG = "CarDriverDistractionManager";
45     private static final int MSG_HANDLE_DISTRACTION_CHANGE = 0;
46 
47     private final IDriverDistractionManager mService;
48     private final EventHandler mEventHandler;
49 
50     private final IDriverDistractionChangeListenerImpl mBinderCallback;
51 
52     /**
53      * Listener to monitor any changes to the driver's distraction level.
54      */
55     public interface OnDriverDistractionChangeListener {
56         /**
57          * Called when the driver's distraction level has changed.
58          *
59          * @param event the new driver distraction information.
60          */
onDriverDistractionChange(DriverDistractionChangeEvent event)61         void onDriverDistractionChange(DriverDistractionChangeEvent event);
62     }
63 
64     private final CopyOnWriteArrayList<OnDriverDistractionChangeListener> mListeners =
65             new CopyOnWriteArrayList<>();
66 
67     /**
68      * Constructor parameters should remain this way for Car library to construct this.
69      */
CarDriverDistractionManager(Car car, IBinder service)70     public CarDriverDistractionManager(Car car, IBinder service) {
71         super(car);
72         mService = IDriverDistractionManager.Stub.asInterface(service);
73         mEventHandler = new EventHandler(this, getEventHandler().getLooper());
74         mBinderCallback = new IDriverDistractionChangeListenerImpl(this);
75     }
76 
77     /**
78      * Gets the current driver distraction level based on the last change event that is not stale.
79      *
80      * Return {@code null} if there is an internal error.
81      */
82     @RequiresPermission(value = ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION)
83     @Nullable
getLastDistractionEvent()84     public DriverDistractionChangeEvent getLastDistractionEvent() {
85         try {
86             return mService.getLastDistractionEvent();
87         } catch (RemoteException e) {
88             return handleRemoteExceptionFromCarService(e, null);
89         }
90     }
91 
92     /**
93      * Adds a {@link OnDriverDistractionChangeListener} to be notified for changes to the driver's
94      * distraction level.
95      *
96      * <p>The provided listener will immediately receive a callback for the most recent distraction
97      * event.
98      *
99      * @param listener to be added
100      */
101     @RequiresPermission(value = ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION)
addDriverDistractionChangeListener( @onNull OnDriverDistractionChangeListener listener)102     public void addDriverDistractionChangeListener(
103             @NonNull OnDriverDistractionChangeListener listener) {
104         if (mListeners.addIfAbsent(listener)) {
105             if (mListeners.size() == 1) {
106                 try {
107                     mService.addDriverDistractionChangeListener(mBinderCallback);
108                 } catch (RemoteException e) {
109                     handleRemoteExceptionFromCarService(e);
110                 }
111             }
112         }
113     }
114 
115     /**
116      * Removes the listener. Listeners not added before will be ignored.
117      */
118     @RequiresPermission(value = ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION)
removeDriverDistractionChangeListener( @onNull OnDriverDistractionChangeListener listener)119     public void removeDriverDistractionChangeListener(
120             @NonNull OnDriverDistractionChangeListener listener) {
121         if (mListeners.remove(listener)) {
122             if (mListeners.size() == 0) {
123                 try {
124                     mService.removeDriverDistractionChangeListener(mBinderCallback);
125                 } catch (RemoteException ignored) {
126                     // ignore for unregistering
127                 }
128             }
129         }
130     }
131 
132     @Override
onCarDisconnected()133     protected void onCarDisconnected() {
134         // nothing to do
135     }
136 
dispatchDistractionChangeToClient( DriverDistractionChangeEvent distractionChangeEvent)137     private void dispatchDistractionChangeToClient(
138             DriverDistractionChangeEvent distractionChangeEvent) {
139         if (distractionChangeEvent == null) {
140             return;
141         }
142         for (OnDriverDistractionChangeListener listener : mListeners) {
143             listener.onDriverDistractionChange(distractionChangeEvent);
144         }
145     }
146 
147     private static final class EventHandler extends Handler {
148         private final WeakReference<CarDriverDistractionManager> mDistractionManager;
149 
EventHandler(CarDriverDistractionManager manager, Looper looper)150         EventHandler(CarDriverDistractionManager manager, Looper looper) {
151             super(looper);
152             mDistractionManager = new WeakReference<>(manager);
153         }
154 
155         @Override
handleMessage(Message msg)156         public void handleMessage(Message msg) {
157             CarDriverDistractionManager mgr = mDistractionManager.get();
158             if (mgr == null) {
159                 Log.e(TAG,
160                         "handleMessage: null reference to distraction manager when handling "
161                                 + "message for " + msg.what);
162                 return;
163             }
164             switch (msg.what) {
165                 case MSG_HANDLE_DISTRACTION_CHANGE:
166                     mgr.dispatchDistractionChangeToClient((DriverDistractionChangeEvent) msg.obj);
167                     break;
168                 default:
169                     Log.e(TAG, "Unknown msg not handled:" + msg.what);
170             }
171         }
172 
dispatchOnDistractionChangedEvent(DriverDistractionChangeEvent event)173         private void dispatchOnDistractionChangedEvent(DriverDistractionChangeEvent event) {
174             sendMessage(obtainMessage(MSG_HANDLE_DISTRACTION_CHANGE, event));
175         }
176     }
177 
178     private static class IDriverDistractionChangeListenerImpl extends
179             IDriverDistractionChangeListener.Stub {
180         private final WeakReference<CarDriverDistractionManager> mDistractionManager;
181 
IDriverDistractionChangeListenerImpl(CarDriverDistractionManager manager)182         IDriverDistractionChangeListenerImpl(CarDriverDistractionManager manager) {
183             mDistractionManager = new WeakReference<>(manager);
184         }
185 
186         @Override
onDriverDistractionChange(DriverDistractionChangeEvent event)187         public void onDriverDistractionChange(DriverDistractionChangeEvent event) {
188             CarDriverDistractionManager manager = mDistractionManager.get();
189             if (manager != null) {
190                 manager.mEventHandler.dispatchOnDistractionChangedEvent(event);
191             }
192         }
193     }
194 }
195