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