Home | History | Annotate | Download | only in property
      1 /*
      2  * Copyright (C) 2016 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.hardware.property;
     18 
     19 import static java.lang.Integer.toHexString;
     20 
     21 import android.annotation.Nullable;
     22 import android.car.Car;
     23 import android.car.CarNotConnectedException;
     24 import android.car.hardware.CarPropertyConfig;
     25 import android.car.hardware.CarPropertyValue;
     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 com.android.internal.annotations.GuardedBy;
     34 
     35 import java.lang.ref.WeakReference;
     36 import java.util.List;
     37 
     38 /**
     39  * API for creating Car*Manager
     40  * @hide
     41  */
     42 public class CarPropertyManagerBase {
     43     private final boolean mDbg;
     44     private final Handler mHandler;
     45     private final ICarProperty mService;
     46     private final String mTag;
     47 
     48     @GuardedBy("mLock")
     49     private ICarPropertyEventListener mListenerToService;
     50     @GuardedBy("mLock")
     51     private CarPropertyEventCallback mCallback;
     52 
     53     private final Object mLock = new Object();
     54 
     55     /** Callback functions for property events */
     56     public interface CarPropertyEventCallback {
     57         /** Called when a property is updated */
     58         void onChangeEvent(CarPropertyValue value);
     59 
     60         /** Called when an error is detected with a property */
     61         void onErrorEvent(int propertyId, int zone);
     62     }
     63 
     64     private final static class EventCallbackHandler extends Handler {
     65         /** Constants handled in the handler */
     66         private static final int MSG_GENERIC_EVENT = 0;
     67 
     68         private final WeakReference<CarPropertyManagerBase> mMgr;
     69 
     70         EventCallbackHandler(CarPropertyManagerBase mgr, Looper looper) {
     71             super(looper);
     72             mMgr = new WeakReference<>(mgr);
     73         }
     74 
     75         @Override
     76         public void handleMessage(Message msg) {
     77             switch (msg.what) {
     78                 case MSG_GENERIC_EVENT:
     79                     CarPropertyManagerBase mgr = mMgr.get();
     80                     if (mgr != null) {
     81                         mgr.dispatchEventToClient((CarPropertyEvent) msg.obj);
     82                     }
     83                     break;
     84                 default:
     85                     Log.e("EventtCallbackHandler", "Event type not handled:  " + msg);
     86                     break;
     87             }
     88         }
     89     }
     90 
     91     /**
     92      * Get an instance of the CarPropertyManagerBase.
     93      */
     94     public CarPropertyManagerBase(IBinder service, Handler handler, boolean dbg,
     95             String tag) {
     96         mDbg = dbg;
     97         mTag = tag;
     98         mService = ICarProperty.Stub.asInterface(service);
     99         mHandler = new EventCallbackHandler(this, handler.getLooper());
    100     }
    101 
    102     public void registerCallback(CarPropertyEventCallback callback)
    103             throws CarNotConnectedException {
    104         synchronized (mLock) {
    105             if (mCallback != null) {
    106                 throw new IllegalStateException("Callback is already registered.");
    107             }
    108 
    109             mCallback = callback;
    110             mListenerToService = new ICarPropertyEventListener.Stub() {
    111                 @Override
    112                 public void onEvent(CarPropertyEvent event) throws RemoteException {
    113                     handleEvent(event);
    114                 }
    115             };
    116         }
    117 
    118         try {
    119             mService.registerListener(mListenerToService);
    120         } catch (RemoteException ex) {
    121             Log.e(mTag, "Could not connect: ", ex);
    122             throw new CarNotConnectedException(ex);
    123         } catch (IllegalStateException ex) {
    124             Car.checkCarNotConnectedExceptionFromCarService(ex);
    125         }
    126     }
    127 
    128     public void unregisterCallback() {
    129         ICarPropertyEventListener listenerToService;
    130         synchronized (mLock) {
    131             listenerToService = mListenerToService;
    132             mCallback = null;
    133             mListenerToService = null;
    134         }
    135 
    136         if (listenerToService == null) {
    137             Log.w(mTag, "unregisterListener: listener was not registered");
    138             return;
    139         }
    140 
    141         try {
    142             mService.unregisterListener(listenerToService);
    143         } catch (RemoteException ex) {
    144             Log.e(mTag, "Failed to unregister listener", ex);
    145             //ignore
    146         } catch (IllegalStateException ex) {
    147             Car.hideCarNotConnectedExceptionFromCarService(ex);
    148         }
    149     }
    150 
    151     /**
    152      * Returns the list of properties available.
    153      *
    154      * @return Caller must check the property type and typecast to the appropriate subclass
    155      * (CarPropertyBooleanProperty, CarPropertyFloatProperty, CarrPropertyIntProperty)
    156      */
    157     public List<CarPropertyConfig> getPropertyList()  throws CarNotConnectedException {
    158         try {
    159             return mService.getPropertyList();
    160         } catch (RemoteException e) {
    161             Log.e(mTag, "Exception in getPropertyList", e);
    162             throw new CarNotConnectedException(e);
    163         }
    164     }
    165 
    166     /**
    167      * Returns value of a bool property
    168      *
    169      * @param prop Property ID to get
    170      * @param area Area of the property to get
    171      */
    172     public boolean getBooleanProperty(int prop, int area) throws CarNotConnectedException {
    173         CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
    174         return carProp != null ? carProp.getValue() : false;
    175     }
    176 
    177     /**
    178      * Returns value of a float property
    179      *
    180      * @param prop Property ID to get
    181      * @param area Area of the property to get
    182      */
    183     public float getFloatProperty(int prop, int area) throws CarNotConnectedException {
    184         CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
    185         return carProp != null ? carProp.getValue() : 0f;
    186     }
    187 
    188     /**
    189      * Returns value of a integer property
    190      *
    191      * @param prop Property ID to get
    192      * @param area Zone of the property to get
    193      */
    194     public int getIntProperty(int prop, int area) throws CarNotConnectedException {
    195         CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
    196         return carProp != null ? carProp.getValue() : 0;
    197     }
    198 
    199     @Nullable
    200     @SuppressWarnings("unchecked")
    201     public <E> CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int area)
    202             throws CarNotConnectedException {
    203         if (mDbg) {
    204             Log.d(mTag, "getProperty, propId: 0x" + toHexString(propId)
    205                     + ", area: 0x" + toHexString(area) + ", class: " + clazz);
    206         }
    207         try {
    208             CarPropertyValue<E> propVal = mService.getProperty(propId, area);
    209             if (propVal != null && propVal.getValue() != null) {
    210                 Class<?> actualClass = propVal.getValue().getClass();
    211                 if (actualClass != clazz) {
    212                     throw new IllegalArgumentException("Invalid property type. " + "Expected: "
    213                             + clazz + ", but was: " + actualClass);
    214                 }
    215             }
    216             return propVal;
    217         } catch (RemoteException e) {
    218             Log.e(mTag, "getProperty failed with " + e.toString()
    219                     + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
    220             throw new CarNotConnectedException(e);
    221         }
    222     }
    223 
    224     public <E> void setProperty(Class<E> clazz, int propId, int area, E val)
    225             throws CarNotConnectedException {
    226         if (mDbg) {
    227             Log.d(mTag, "setProperty, propId: 0x" + toHexString(propId)
    228                     + ", area: 0x" + toHexString(area) + ", class: " + clazz + ", val: " + val);
    229         }
    230         try {
    231             mService.setProperty(new CarPropertyValue<>(propId, area, val));
    232         } catch (RemoteException e) {
    233             Log.e(mTag, "setProperty failed with " + e.toString(), e);
    234             throw new CarNotConnectedException(e);
    235         }
    236     }
    237 
    238     /**
    239      * Modifies a property.  If the property modification doesn't occur, an error event shall be
    240      * generated and propagated back to the application.
    241      *
    242      * @param prop Property ID to modify
    243      * @param area Area to apply the modification.
    244      * @param val Value to set
    245      */
    246     public void setBooleanProperty(int prop, int area, boolean val)
    247             throws CarNotConnectedException {
    248         setProperty(Boolean.class, prop, area, val);
    249     }
    250 
    251     public void setFloatProperty(int prop, int area, float val) throws CarNotConnectedException {
    252         setProperty(Float.class, prop, area, val);
    253     }
    254 
    255     public void setIntProperty(int prop, int area, int val) throws CarNotConnectedException {
    256         setProperty(Integer.class, prop, area, val);
    257     }
    258 
    259     private void dispatchEventToClient(CarPropertyEvent event) {
    260         CarPropertyEventCallback listener;
    261         synchronized (mLock) {
    262             listener = mCallback;
    263         }
    264 
    265         if (listener == null) {
    266             Log.e(mTag, "Listener died, not dispatching event.");
    267             return;
    268         }
    269 
    270         CarPropertyValue propVal = event.getCarPropertyValue();
    271         switch(event.getEventType()) {
    272             case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
    273                 listener.onChangeEvent(propVal);
    274                 break;
    275             case CarPropertyEvent.PROPERTY_EVENT_ERROR:
    276                 listener.onErrorEvent(propVal.getPropertyId(), propVal.getAreaId());
    277                 break;
    278             default:
    279                 throw new IllegalArgumentException();
    280         }
    281     }
    282 
    283     private void handleEvent(CarPropertyEvent event) {
    284         mHandler.sendMessage(mHandler.obtainMessage(EventCallbackHandler.MSG_GENERIC_EVENT, event));
    285     }
    286 
    287     /** @hide */
    288     public void onCarDisconnected() {
    289 
    290         ICarPropertyEventListener listenerToService;
    291         synchronized (mLock) {
    292             listenerToService = mListenerToService;
    293         }
    294 
    295         if (listenerToService != null) {
    296             unregisterCallback();
    297         }
    298     }
    299 }
    300