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