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