blob: 8c2a24fde35a601d779b151c28277f41023048c4 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.car.drivingstate;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.car.Car;
import android.car.CarManagerBase;
import android.car.CarNotConnectedException;
import android.car.drivingstate.ICarDrivingState;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import java.lang.ref.WeakReference;
/**
* API to register and get driving state related information in a car.
* @hide
*/
@SystemApi
public final class CarDrivingStateManager implements CarManagerBase {
private static final String TAG = "CarDrivingStateMgr";
private static final boolean DBG = false;
private static final boolean VDBG = false;
private static final int MSG_HANDLE_DRIVING_STATE_CHANGE = 0;
private final Context mContext;
private final ICarDrivingState mDrivingService;
private final EventCallbackHandler mEventCallbackHandler;
private CarDrivingStateEventListener mDrvStateEventListener;
private CarDrivingStateChangeListenerToService mListenerToService;
/** @hide */
public CarDrivingStateManager(IBinder service, Context context, Handler handler) {
mContext = context;
mDrivingService = ICarDrivingState.Stub.asInterface(service);
mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
}
/** @hide */
@Override
public synchronized void onCarDisconnected() {
mListenerToService = null;
mDrvStateEventListener = null;
}
/**
* Listener Interface for clients to implement to get updated on driving state changes.
*/
public interface CarDrivingStateEventListener {
/**
* Called when the car's driving state changes.
* @param event Car's driving state.
*/
void onDrivingStateChanged(CarDrivingStateEvent event);
}
/**
* Register a {@link CarDrivingStateEventListener} to listen for driving state changes.
*
* @param listener {@link CarDrivingStateEventListener}
*/
public synchronized void registerListener(@NonNull CarDrivingStateEventListener listener)
throws CarNotConnectedException, IllegalArgumentException {
if (listener == null) {
if (VDBG) {
Log.v(TAG, "registerCarDrivingStateEventListener(): null listener");
}
throw new IllegalArgumentException("Listener is null");
}
// Check if the listener has been already registered for this event type
if (mDrvStateEventListener != null) {
if (DBG) {
Log.d(TAG, "Listener already registered");
}
return;
}
mDrvStateEventListener = listener;
try {
if (mListenerToService == null) {
mListenerToService = new CarDrivingStateChangeListenerToService(this);
}
// register to the Service for getting notified
mDrivingService.registerDrivingStateChangeListener(mListenerToService);
} catch (RemoteException e) {
Log.e(TAG, "Could not register a listener to Driving State Service " + e);
throw new CarNotConnectedException(e);
} catch (IllegalStateException e) {
Log.e(TAG, "Could not register a listener to Driving State Service " + e);
Car.checkCarNotConnectedExceptionFromCarService(e);
}
}
/**
* Unregister the registered {@link CarDrivingStateEventListener} for the given driving event
* type.
*/
public synchronized void unregisterListener()
throws CarNotConnectedException {
if (mDrvStateEventListener == null) {
if (DBG) {
Log.d(TAG, "Listener was not previously registered");
}
return;
}
try {
mDrivingService.unregisterDrivingStateChangeListener(mListenerToService);
mDrvStateEventListener = null;
mListenerToService = null;
} catch (RemoteException e) {
Log.e(TAG, "Could not unregister listener from Driving State Service " + e);
throw new CarNotConnectedException(e);
}
}
/**
* Get the current value of the car's driving state.
*
* @return {@link CarDrivingStateEvent} corresponding to the given eventType
*/
@Nullable
public CarDrivingStateEvent getCurrentCarDrivingState()
throws CarNotConnectedException {
try {
return mDrivingService.getCurrentDrivingState();
} catch (RemoteException e) {
Log.e(TAG, "Could not get current driving state " + e);
throw new CarNotConnectedException(e);
}
}
/**
* Class that implements the listener interface and gets called back from the
* {@link com.android.car.CarDrivingStateService} across the binder interface.
*/
private static class CarDrivingStateChangeListenerToService extends
ICarDrivingStateChangeListener.Stub {
private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
public CarDrivingStateChangeListenerToService(CarDrivingStateManager manager) {
mDrvStateMgr = new WeakReference<>(manager);
}
@Override
public void onDrivingStateChanged(CarDrivingStateEvent event) {
CarDrivingStateManager manager = mDrvStateMgr.get();
if (manager != null) {
manager.handleDrivingStateChanged(event);
}
}
}
/**
* Gets the {@link CarDrivingStateEvent} from the service listener
* {@link CarDrivingStateChangeListenerToService} and dispatches it to a handler provided
* to the manager
*
* @param event {@link CarDrivingStateEvent} that has been registered to listen on
*/
private void handleDrivingStateChanged(CarDrivingStateEvent event) {
// send a message to the handler
mEventCallbackHandler.sendMessage(
mEventCallbackHandler.obtainMessage(MSG_HANDLE_DRIVING_STATE_CHANGE, event));
}
/**
* Callback Handler to handle dispatching the driving state changes to the corresponding
* listeners
*/
private static final class EventCallbackHandler extends Handler {
private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
public EventCallbackHandler(CarDrivingStateManager manager, Looper looper) {
super(looper);
mDrvStateMgr = new WeakReference<>(manager);
}
@Override
public void handleMessage(Message msg) {
CarDrivingStateManager mgr = mDrvStateMgr.get();
if (mgr != null) {
mgr.dispatchDrivingStateChangeToClient((CarDrivingStateEvent) msg.obj);
}
}
}
/**
* Checks for the listener to {@link CarDrivingStateEvent} and calls it back
* in the callback handler thread
*
* @param event {@link CarDrivingStateEvent}
*/
private void dispatchDrivingStateChangeToClient(CarDrivingStateEvent event) {
if (event == null) {
return;
}
CarDrivingStateEventListener listener;
synchronized (this) {
listener = mDrvStateEventListener;
}
if (listener != null) {
listener.onDrivingStateChanged(event);
}
}
}