Home | History | Annotate | Download | only in drivingstate
      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.car.Car;
     22 import android.car.CarManagerBase;
     23 import android.car.CarNotConnectedException;
     24 import android.car.drivingstate.ICarUxRestrictionsManager;
     25 import android.content.Context;
     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.util.Log;
     32 
     33 import java.lang.ref.WeakReference;
     34 
     35 /**
     36  * API to register and get the User Experience restrictions imposed based on the car's driving
     37  * state.
     38  */
     39 public final class CarUxRestrictionsManager implements CarManagerBase {
     40     private static final String TAG = "CarUxRManager";
     41     private static final boolean DBG = false;
     42     private static final boolean VDBG = false;
     43     private static final int MSG_HANDLE_UX_RESTRICTIONS_CHANGE = 0;
     44 
     45     private final Context mContext;
     46     private final ICarUxRestrictionsManager mUxRService;
     47     private final EventCallbackHandler mEventCallbackHandler;
     48     private OnUxRestrictionsChangedListener mUxRListener;
     49     private CarUxRestrictionsChangeListenerToService mListenerToService;
     50 
     51 
     52     /** @hide */
     53     public CarUxRestrictionsManager(IBinder service, Context context, Handler handler) {
     54         mContext = context;
     55         mUxRService = ICarUxRestrictionsManager.Stub.asInterface(service);
     56         mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
     57     }
     58 
     59     /** @hide */
     60     @Override
     61     public synchronized void onCarDisconnected() {
     62         mListenerToService = null;
     63         mUxRListener = null;
     64     }
     65 
     66     /**
     67      * Listener Interface for clients to implement to get updated on driving state related
     68      * changes.
     69      */
     70     public interface OnUxRestrictionsChangedListener {
     71         /**
     72          * Called when the UX restrictions due to a car's driving state changes.
     73          *
     74          * @param restrictionInfo The new UX restriction information
     75          */
     76         void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo);
     77     }
     78 
     79     /**
     80      * Register a {@link OnUxRestrictionsChangedListener} for listening to changes in the
     81      * UX Restrictions to adhere to.
     82      * <p>
     83      * If a listener has already been registered, it has to be unregistered before registering
     84      * the new one.
     85      *
     86      * @param listener {@link OnUxRestrictionsChangedListener}
     87      */
     88     public synchronized void registerListener(@NonNull OnUxRestrictionsChangedListener listener)
     89             throws CarNotConnectedException, IllegalArgumentException {
     90         if (listener == null) {
     91             if (VDBG) {
     92                 Log.v(TAG, "registerListener(): null listener");
     93             }
     94             throw new IllegalArgumentException("Listener is null");
     95         }
     96         // Check if the listener has been already registered.
     97         if (mUxRListener != null) {
     98             if (DBG) {
     99                 Log.d(TAG, "Listener already registered listener");
    100             }
    101             return;
    102         }
    103         mUxRListener = listener;
    104         try {
    105             if (mListenerToService == null) {
    106                 mListenerToService = new CarUxRestrictionsChangeListenerToService(this);
    107             }
    108             // register to the Service to listen for changes.
    109             mUxRService.registerUxRestrictionsChangeListener(mListenerToService);
    110         } catch (RemoteException e) {
    111             Log.e(TAG, "Could not register a listener to CarUxRestrictionsManagerService " + e);
    112             throw new CarNotConnectedException(e);
    113         } catch (IllegalStateException e) {
    114             Log.e(TAG, "Could not register a listener to CarUxRestrictionsManagerService " + e);
    115             Car.checkCarNotConnectedExceptionFromCarService(e);
    116         }
    117     }
    118 
    119     /**
    120      * Unregister the registered {@link OnUxRestrictionsChangedListener}
    121      */
    122     public synchronized void unregisterListener()
    123             throws CarNotConnectedException {
    124         if (mUxRListener == null) {
    125             if (DBG) {
    126                 Log.d(TAG, "Listener was not previously registered");
    127             }
    128             return;
    129         }
    130         try {
    131             mUxRService.unregisterUxRestrictionsChangeListener(mListenerToService);
    132             mUxRListener = null;
    133         } catch (RemoteException e) {
    134             Log.e(TAG, "Could not unregister listener from Driving State Service " + e);
    135             throw new CarNotConnectedException(e);
    136         }
    137     }
    138 
    139     /**
    140      * Get the current UX restrictions {@link CarUxRestrictions} in place.
    141      *
    142      * @return current UX restrictions that is in effect.
    143      */
    144     @Nullable
    145     public CarUxRestrictions getCurrentCarUxRestrictions()
    146             throws CarNotConnectedException {
    147         try {
    148             return mUxRService.getCurrentUxRestrictions();
    149         } catch (RemoteException e) {
    150             Log.e(TAG, "Could not get current UX restrictions " + e);
    151             throw new CarNotConnectedException(e);
    152         }
    153     }
    154 
    155     /**
    156      * Class that implements the listener interface and gets called back from the
    157      * {@link com.android.car.CarDrivingStateService} across the binder interface.
    158      */
    159     private static class CarUxRestrictionsChangeListenerToService extends
    160             ICarUxRestrictionsChangeListener.Stub {
    161         private final WeakReference<CarUxRestrictionsManager> mUxRestrictionsManager;
    162 
    163         public CarUxRestrictionsChangeListenerToService(CarUxRestrictionsManager manager) {
    164             mUxRestrictionsManager = new WeakReference<>(manager);
    165         }
    166 
    167         @Override
    168         public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
    169             CarUxRestrictionsManager manager = mUxRestrictionsManager.get();
    170             if (manager != null) {
    171                 manager.handleUxRestrictionsChanged(restrictionInfo);
    172             }
    173         }
    174     }
    175 
    176     /**
    177      * Gets the {@link CarUxRestrictions} from the service listener
    178      * {@link CarUxRestrictionsChangeListenerToService} and dispatches it to a handler provided
    179      * to the manager
    180      *
    181      * @param restrictionInfo {@link CarUxRestrictions} that has been registered to listen on
    182      */
    183     private void handleUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
    184         // send a message to the handler
    185         mEventCallbackHandler.sendMessage(mEventCallbackHandler.obtainMessage(
    186                 MSG_HANDLE_UX_RESTRICTIONS_CHANGE, restrictionInfo));
    187     }
    188 
    189     /**
    190      * Callback Handler to handle dispatching the UX restriction changes to the corresponding
    191      * listeners
    192      */
    193     private static final class EventCallbackHandler extends Handler {
    194         private final WeakReference<CarUxRestrictionsManager> mUxRestrictionsManager;
    195 
    196         public EventCallbackHandler(CarUxRestrictionsManager manager, Looper looper) {
    197             super(looper);
    198             mUxRestrictionsManager = new WeakReference<>(manager);
    199         }
    200 
    201         @Override
    202         public void handleMessage(Message msg) {
    203             CarUxRestrictionsManager mgr = mUxRestrictionsManager.get();
    204             if (mgr != null) {
    205                 mgr.dispatchUxRChangeToClient((CarUxRestrictions) msg.obj);
    206             }
    207         }
    208 
    209     }
    210 
    211     /**
    212      * Checks for the listeners to list of {@link CarUxRestrictions} and calls them back
    213      * in the callback handler thread
    214      *
    215      * @param restrictionInfo {@link CarUxRestrictions}
    216      */
    217     private void dispatchUxRChangeToClient(CarUxRestrictions restrictionInfo) {
    218         if (restrictionInfo == null) {
    219             return;
    220         }
    221         OnUxRestrictionsChangedListener listener;
    222         synchronized (this) {
    223             listener = mUxRListener;
    224         }
    225         if (listener != null) {
    226             listener.onUxRestrictionsChanged(restrictionInfo);
    227         }
    228     }
    229 }
    230