Home | History | Annotate | Download | only in hardware
      1     /*
      2  * Copyright (C) 2012 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.hardware;
     18 
     19 import android.content.Context;
     20 import android.os.Handler;
     21 import android.os.Looper;
     22 import android.os.MessageQueue;
     23 import android.util.Log;
     24 import android.util.SparseArray;
     25 import android.util.SparseBooleanArray;
     26 import android.util.SparseIntArray;
     27 import dalvik.system.CloseGuard;
     28 
     29 import java.util.ArrayList;
     30 import java.util.HashMap;
     31 import java.util.List;
     32 
     33 /**
     34  * Sensor manager implementation that communicates with the built-in
     35  * system sensors.
     36  *
     37  * @hide
     38  */
     39 public class SystemSensorManager extends SensorManager {
     40     private static native void nativeClassInit();
     41     private static native int nativeGetNextSensor(Sensor sensor, int next);
     42 
     43     private static boolean sSensorModuleInitialized = false;
     44     private static final Object sSensorModuleLock = new Object();
     45     private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
     46     private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
     47 
     48     // Listener list
     49     private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
     50             new HashMap<SensorEventListener, SensorEventQueue>();
     51     private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
     52             new HashMap<TriggerEventListener, TriggerEventQueue>();
     53 
     54     // Looper associated with the context in which this instance was created.
     55     private final Looper mMainLooper;
     56     private final int mTargetSdkLevel;
     57 
     58     /** {@hide} */
     59     public SystemSensorManager(Context context, Looper mainLooper) {
     60         mMainLooper = mainLooper;
     61         mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
     62         synchronized(sSensorModuleLock) {
     63             if (!sSensorModuleInitialized) {
     64                 sSensorModuleInitialized = true;
     65 
     66                 nativeClassInit();
     67 
     68                 // initialize the sensor list
     69                 final ArrayList<Sensor> fullList = sFullSensorsList;
     70                 int i = 0;
     71                 do {
     72                     Sensor sensor = new Sensor();
     73                     i = nativeGetNextSensor(sensor, i);
     74                     if (i>=0) {
     75                         //Log.d(TAG, "found sensor: " + sensor.getName() +
     76                         //        ", handle=" + sensor.getHandle());
     77                         fullList.add(sensor);
     78                         sHandleToSensor.append(sensor.getHandle(), sensor);
     79                     }
     80                 } while (i>0);
     81             }
     82         }
     83     }
     84 
     85 
     86     /** @hide */
     87     @Override
     88     protected List<Sensor> getFullSensorList() {
     89         return sFullSensorsList;
     90     }
     91 
     92 
     93     /** @hide */
     94     @Override
     95     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
     96             int delay, Handler handler)
     97     {
     98         // Invariants to preserve:
     99         // - one Looper per SensorEventListener
    100         // - one Looper per SensorEventQueue
    101         // We map SensorEventListener to a SensorEventQueue, which holds the looper
    102         if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
    103 
    104         // Trigger Sensors should use the requestTriggerSensor call.
    105         if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) return false;
    106 
    107         synchronized (mSensorListeners) {
    108             SensorEventQueue queue = mSensorListeners.get(listener);
    109             if (queue == null) {
    110                 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
    111                 queue = new SensorEventQueue(listener, looper, this);
    112                 if (!queue.addSensor(sensor, delay)) {
    113                     queue.dispose();
    114                     return false;
    115                 }
    116                 mSensorListeners.put(listener, queue);
    117                 return true;
    118             } else {
    119                 return queue.addSensor(sensor, delay);
    120             }
    121         }
    122     }
    123 
    124     /** @hide */
    125     @Override
    126     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
    127         // Trigger Sensors should use the cancelTriggerSensor call.
    128         if (sensor != null && Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
    129             return;
    130         }
    131 
    132         synchronized (mSensorListeners) {
    133             SensorEventQueue queue = mSensorListeners.get(listener);
    134             if (queue != null) {
    135                 boolean result;
    136                 if (sensor == null) {
    137                     result = queue.removeAllSensors();
    138                 } else {
    139                     result = queue.removeSensor(sensor, true);
    140                 }
    141                 if (result && !queue.hasSensors()) {
    142                     mSensorListeners.remove(listener);
    143                     queue.dispose();
    144                 }
    145             }
    146         }
    147     }
    148 
    149     /** @hide */
    150     @Override
    151     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
    152         if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
    153 
    154         if (Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) return false;
    155 
    156         synchronized (mTriggerListeners) {
    157             TriggerEventQueue queue = mTriggerListeners.get(listener);
    158             if (queue == null) {
    159                 queue = new TriggerEventQueue(listener, mMainLooper, this);
    160                 if (!queue.addSensor(sensor, 0)) {
    161                     queue.dispose();
    162                     return false;
    163                 }
    164                 mTriggerListeners.put(listener, queue);
    165                 return true;
    166             } else {
    167                 return queue.addSensor(sensor, 0);
    168             }
    169         }
    170     }
    171 
    172     /** @hide */
    173     @Override
    174     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
    175             boolean disable) {
    176         if (sensor != null && Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) {
    177             return false;
    178         }
    179         synchronized (mTriggerListeners) {
    180             TriggerEventQueue queue = mTriggerListeners.get(listener);
    181             if (queue != null) {
    182                 boolean result;
    183                 if (sensor == null) {
    184                     result = queue.removeAllSensors();
    185                 } else {
    186                     result = queue.removeSensor(sensor, disable);
    187                 }
    188                 if (result && !queue.hasSensors()) {
    189                     mTriggerListeners.remove(listener);
    190                     queue.dispose();
    191                 }
    192                 return result;
    193             }
    194             return false;
    195         }
    196     }
    197 
    198     /*
    199      * BaseEventQueue is the communication channel with the sensor service,
    200      * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
    201      * the queues and the listeners.
    202      */
    203     private static abstract class BaseEventQueue {
    204         private native int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
    205 
    206                 float[] scratch);
    207         private static native int nativeEnableSensor(int eventQ, int handle, int us);
    208         private static native int nativeDisableSensor(int eventQ, int handle);
    209         private static native void nativeDestroySensorEventQueue(int eventQ);
    210         private int nSensorEventQueue;
    211         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
    212         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
    213         protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
    214         private final CloseGuard mCloseGuard = CloseGuard.get();
    215         private final float[] mScratch = new float[16];
    216         protected final SystemSensorManager mManager;
    217 
    218         BaseEventQueue(Looper looper, SystemSensorManager manager) {
    219             nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch);
    220             mCloseGuard.open("dispose");
    221             mManager = manager;
    222         }
    223 
    224         public void dispose() {
    225             dispose(false);
    226         }
    227 
    228         public boolean addSensor(Sensor sensor, int delay) {
    229             // Check if already present.
    230             int handle = sensor.getHandle();
    231             if (mActiveSensors.get(handle)) return false;
    232 
    233             // Get ready to receive events before calling enable.
    234             mActiveSensors.put(handle, true);
    235             addSensorEvent(sensor);
    236             if (enableSensor(sensor, delay) != 0) {
    237                 removeSensor(sensor, false);
    238                 return false;
    239             }
    240             return true;
    241         }
    242 
    243         public boolean removeAllSensors() {
    244             for (int i=0 ; i<mActiveSensors.size(); i++) {
    245                 if (mActiveSensors.valueAt(i) == true) {
    246                     int handle = mActiveSensors.keyAt(i);
    247                     Sensor sensor = sHandleToSensor.get(handle);
    248                     if (sensor != null) {
    249                         disableSensor(sensor);
    250                         mActiveSensors.put(handle, false);
    251                         removeSensorEvent(sensor);
    252                     } else {
    253                         // it should never happen -- just ignore.
    254                     }
    255                 }
    256             }
    257             return true;
    258         }
    259 
    260         public boolean removeSensor(Sensor sensor, boolean disable) {
    261             final int handle = sensor.getHandle();
    262             if (mActiveSensors.get(handle)) {
    263                 if (disable) disableSensor(sensor);
    264                 mActiveSensors.put(sensor.getHandle(), false);
    265                 removeSensorEvent(sensor);
    266                 return true;
    267             }
    268             return false;
    269         }
    270 
    271         public boolean hasSensors() {
    272             // no more sensors are set
    273             return mActiveSensors.indexOfValue(true) >= 0;
    274         }
    275 
    276         @Override
    277         protected void finalize() throws Throwable {
    278             try {
    279                 dispose(true);
    280             } finally {
    281                 super.finalize();
    282             }
    283         }
    284 
    285         private void dispose(boolean finalized) {
    286             if (mCloseGuard != null) {
    287                 if (finalized) {
    288                     mCloseGuard.warnIfOpen();
    289                 }
    290                 mCloseGuard.close();
    291             }
    292             if (nSensorEventQueue != 0) {
    293                 nativeDestroySensorEventQueue(nSensorEventQueue);
    294                 nSensorEventQueue = 0;
    295             }
    296         }
    297 
    298         private int enableSensor(Sensor sensor, int us) {
    299             if (nSensorEventQueue == 0) throw new NullPointerException();
    300             if (sensor == null) throw new NullPointerException();
    301             return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us);
    302         }
    303         private int disableSensor(Sensor sensor) {
    304             if (nSensorEventQueue == 0) throw new NullPointerException();
    305             if (sensor == null) throw new NullPointerException();
    306             return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
    307         }
    308         protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
    309                 long timestamp);
    310 
    311         protected abstract void addSensorEvent(Sensor sensor);
    312         protected abstract void removeSensorEvent(Sensor sensor);
    313     }
    314 
    315     static final class SensorEventQueue extends BaseEventQueue {
    316         private final SensorEventListener mListener;
    317         private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
    318 
    319         public SensorEventQueue(SensorEventListener listener, Looper looper,
    320                 SystemSensorManager manager) {
    321             super(looper, manager);
    322             mListener = listener;
    323         }
    324 
    325         public void addSensorEvent(Sensor sensor) {
    326             SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
    327                     mManager.mTargetSdkLevel));
    328             mSensorsEvents.put(sensor.getHandle(), t);
    329         }
    330 
    331         public void removeSensorEvent(Sensor sensor) {
    332             mSensorsEvents.delete(sensor.getHandle());
    333         }
    334 
    335         // Called from native code.
    336         @SuppressWarnings("unused")
    337         @Override
    338         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
    339                 long timestamp) {
    340             final Sensor sensor = sHandleToSensor.get(handle);
    341             SensorEvent t = mSensorsEvents.get(handle);
    342             if (t == null) {
    343                 Log.e(TAG, "Error: Sensor Event is null for Sensor: " + sensor);
    344                 return;
    345             }
    346             // Copy from the values array.
    347             System.arraycopy(values, 0, t.values, 0, t.values.length);
    348             t.timestamp = timestamp;
    349             t.accuracy = inAccuracy;
    350             t.sensor = sensor;
    351             switch (t.sensor.getType()) {
    352                 // Only report accuracy for sensors that support it.
    353                 case Sensor.TYPE_MAGNETIC_FIELD:
    354                 case Sensor.TYPE_ORIENTATION:
    355                     // call onAccuracyChanged() only if the value changes
    356                     final int accuracy = mSensorAccuracies.get(handle);
    357                     if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
    358                         mSensorAccuracies.put(handle, t.accuracy);
    359                         mListener.onAccuracyChanged(t.sensor, t.accuracy);
    360                     }
    361                     break;
    362                 default:
    363                     // For other sensors, just report the accuracy once
    364                     if (mFirstEvent.get(handle) == false) {
    365                         mFirstEvent.put(handle, true);
    366                         mListener.onAccuracyChanged(
    367                                 t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
    368                     }
    369                     break;
    370             }
    371             mListener.onSensorChanged(t);
    372         }
    373     }
    374 
    375     static final class TriggerEventQueue extends BaseEventQueue {
    376         private final TriggerEventListener mListener;
    377         private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
    378 
    379         public TriggerEventQueue(TriggerEventListener listener, Looper looper,
    380                 SystemSensorManager manager) {
    381             super(looper, manager);
    382             mListener = listener;
    383         }
    384 
    385         public void addSensorEvent(Sensor sensor) {
    386             TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
    387                     mManager.mTargetSdkLevel));
    388             mTriggerEvents.put(sensor.getHandle(), t);
    389         }
    390 
    391         public void removeSensorEvent(Sensor sensor) {
    392             mTriggerEvents.delete(sensor.getHandle());
    393         }
    394 
    395         // Called from native code.
    396         @SuppressWarnings("unused")
    397         @Override
    398         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
    399                 long timestamp) {
    400             final Sensor sensor = sHandleToSensor.get(handle);
    401             TriggerEvent t = mTriggerEvents.get(handle);
    402             if (t == null) {
    403                 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
    404                 return;
    405             }
    406 
    407             // Copy from the values array.
    408             System.arraycopy(values, 0, t.values, 0, t.values.length);
    409             t.timestamp = timestamp;
    410             t.sensor = sensor;
    411 
    412             // A trigger sensor is auto disabled. So just clean up and don't call native
    413             // disable.
    414             mManager.cancelTriggerSensorImpl(mListener, sensor, false);
    415 
    416             mListener.onTrigger(t);
    417         }
    418     }
    419 }
    420