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