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 delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
     97         if (listener == null || sensor == null) {
     98             Log.e(TAG, "sensor or listener is null");
     99             return false;
    100         }
    101         // Trigger Sensors should use the requestTriggerSensor call.
    102         if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
    103             Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
    104             return false;
    105         }
    106         if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
    107             Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
    108             return false;
    109         }
    110 
    111         // Invariants to preserve:
    112         // - one Looper per SensorEventListener
    113         // - one Looper per SensorEventQueue
    114         // We map SensorEventListener to a SensorEventQueue, which holds the looper
    115         synchronized (mSensorListeners) {
    116             SensorEventQueue queue = mSensorListeners.get(listener);
    117             if (queue == null) {
    118                 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
    119                 queue = new SensorEventQueue(listener, looper, this);
    120                 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) {
    121                     queue.dispose();
    122                     return false;
    123                 }
    124                 mSensorListeners.put(listener, queue);
    125                 return true;
    126             } else {
    127                 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags);
    128             }
    129         }
    130     }
    131 
    132     /** @hide */
    133     @Override
    134     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
    135         // Trigger Sensors should use the cancelTriggerSensor call.
    136         if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
    137             return;
    138         }
    139 
    140         synchronized (mSensorListeners) {
    141             SensorEventQueue queue = mSensorListeners.get(listener);
    142             if (queue != null) {
    143                 boolean result;
    144                 if (sensor == null) {
    145                     result = queue.removeAllSensors();
    146                 } else {
    147                     result = queue.removeSensor(sensor, true);
    148                 }
    149                 if (result && !queue.hasSensors()) {
    150                     mSensorListeners.remove(listener);
    151                     queue.dispose();
    152                 }
    153             }
    154         }
    155     }
    156 
    157     /** @hide */
    158     @Override
    159     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
    160         if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
    161 
    162         if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
    163 
    164         synchronized (mTriggerListeners) {
    165             TriggerEventQueue queue = mTriggerListeners.get(listener);
    166             if (queue == null) {
    167                 queue = new TriggerEventQueue(listener, mMainLooper, this);
    168                 if (!queue.addSensor(sensor, 0, 0, 0)) {
    169                     queue.dispose();
    170                     return false;
    171                 }
    172                 mTriggerListeners.put(listener, queue);
    173                 return true;
    174             } else {
    175                 return queue.addSensor(sensor, 0, 0, 0);
    176             }
    177         }
    178     }
    179 
    180     /** @hide */
    181     @Override
    182     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
    183             boolean disable) {
    184         if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
    185             return false;
    186         }
    187         synchronized (mTriggerListeners) {
    188             TriggerEventQueue queue = mTriggerListeners.get(listener);
    189             if (queue != null) {
    190                 boolean result;
    191                 if (sensor == null) {
    192                     result = queue.removeAllSensors();
    193                 } else {
    194                     result = queue.removeSensor(sensor, disable);
    195                 }
    196                 if (result && !queue.hasSensors()) {
    197                     mTriggerListeners.remove(listener);
    198                     queue.dispose();
    199                 }
    200                 return result;
    201             }
    202             return false;
    203         }
    204     }
    205 
    206     protected boolean flushImpl(SensorEventListener listener) {
    207         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
    208 
    209         synchronized (mSensorListeners) {
    210             SensorEventQueue queue = mSensorListeners.get(listener);
    211             if (queue == null) {
    212                 return false;
    213             } else {
    214                 return (queue.flush() == 0);
    215             }
    216         }
    217     }
    218 
    219     /*
    220      * BaseEventQueue is the communication channel with the sensor service,
    221      * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
    222      * the queues and the listeners.
    223      */
    224     private static abstract class BaseEventQueue {
    225         private native long nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
    226                 float[] scratch);
    227         private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
    228                 int maxBatchReportLatencyUs, int reservedFlags);
    229         private static native int nativeDisableSensor(long eventQ, int handle);
    230         private static native void nativeDestroySensorEventQueue(long eventQ);
    231         private static native int nativeFlushSensor(long eventQ);
    232         private long nSensorEventQueue;
    233         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
    234         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
    235         protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
    236         private final CloseGuard mCloseGuard = CloseGuard.get();
    237         private final float[] mScratch = new float[16];
    238         protected final SystemSensorManager mManager;
    239 
    240         BaseEventQueue(Looper looper, SystemSensorManager manager) {
    241             nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch);
    242             mCloseGuard.open("dispose");
    243             mManager = manager;
    244         }
    245 
    246         public void dispose() {
    247             dispose(false);
    248         }
    249 
    250         public boolean addSensor(
    251                 Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) {
    252             // Check if already present.
    253             int handle = sensor.getHandle();
    254             if (mActiveSensors.get(handle)) return false;
    255 
    256             // Get ready to receive events before calling enable.
    257             mActiveSensors.put(handle, true);
    258             addSensorEvent(sensor);
    259             if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) {
    260                 // Try continuous mode if batching fails.
    261                 if (maxBatchReportLatencyUs == 0 ||
    262                     maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) {
    263                   removeSensor(sensor, false);
    264                   return false;
    265                 }
    266             }
    267             return true;
    268         }
    269 
    270         public boolean removeAllSensors() {
    271             for (int i=0 ; i<mActiveSensors.size(); i++) {
    272                 if (mActiveSensors.valueAt(i) == true) {
    273                     int handle = mActiveSensors.keyAt(i);
    274                     Sensor sensor = sHandleToSensor.get(handle);
    275                     if (sensor != null) {
    276                         disableSensor(sensor);
    277                         mActiveSensors.put(handle, false);
    278                         removeSensorEvent(sensor);
    279                     } else {
    280                         // it should never happen -- just ignore.
    281                     }
    282                 }
    283             }
    284             return true;
    285         }
    286 
    287         public boolean removeSensor(Sensor sensor, boolean disable) {
    288             final int handle = sensor.getHandle();
    289             if (mActiveSensors.get(handle)) {
    290                 if (disable) disableSensor(sensor);
    291                 mActiveSensors.put(sensor.getHandle(), false);
    292                 removeSensorEvent(sensor);
    293                 return true;
    294             }
    295             return false;
    296         }
    297 
    298         public int flush() {
    299             if (nSensorEventQueue == 0) throw new NullPointerException();
    300             return nativeFlushSensor(nSensorEventQueue);
    301         }
    302 
    303         public boolean hasSensors() {
    304             // no more sensors are set
    305             return mActiveSensors.indexOfValue(true) >= 0;
    306         }
    307 
    308         @Override
    309         protected void finalize() throws Throwable {
    310             try {
    311                 dispose(true);
    312             } finally {
    313                 super.finalize();
    314             }
    315         }
    316 
    317         private void dispose(boolean finalized) {
    318             if (mCloseGuard != null) {
    319                 if (finalized) {
    320                     mCloseGuard.warnIfOpen();
    321                 }
    322                 mCloseGuard.close();
    323             }
    324             if (nSensorEventQueue != 0) {
    325                 nativeDestroySensorEventQueue(nSensorEventQueue);
    326                 nSensorEventQueue = 0;
    327             }
    328         }
    329 
    330         private int enableSensor(
    331                 Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) {
    332             if (nSensorEventQueue == 0) throw new NullPointerException();
    333             if (sensor == null) throw new NullPointerException();
    334             return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
    335                     maxBatchReportLatencyUs, reservedFlags);
    336         }
    337 
    338         private int disableSensor(Sensor sensor) {
    339             if (nSensorEventQueue == 0) throw new NullPointerException();
    340             if (sensor == null) throw new NullPointerException();
    341             return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
    342         }
    343         protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
    344                 long timestamp);
    345         protected abstract void dispatchFlushCompleteEvent(int handle);
    346 
    347         protected abstract void addSensorEvent(Sensor sensor);
    348         protected abstract void removeSensorEvent(Sensor sensor);
    349     }
    350 
    351     static final class SensorEventQueue extends BaseEventQueue {
    352         private final SensorEventListener mListener;
    353         private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
    354 
    355         public SensorEventQueue(SensorEventListener listener, Looper looper,
    356                 SystemSensorManager manager) {
    357             super(looper, manager);
    358             mListener = listener;
    359         }
    360 
    361         @Override
    362         public void addSensorEvent(Sensor sensor) {
    363             SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
    364                     mManager.mTargetSdkLevel));
    365             synchronized (mSensorsEvents) {
    366                 mSensorsEvents.put(sensor.getHandle(), t);
    367             }
    368         }
    369 
    370         @Override
    371         public void removeSensorEvent(Sensor sensor) {
    372             synchronized (mSensorsEvents) {
    373                 mSensorsEvents.delete(sensor.getHandle());
    374             }
    375         }
    376 
    377         // Called from native code.
    378         @SuppressWarnings("unused")
    379         @Override
    380         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
    381                 long timestamp) {
    382             final Sensor sensor = sHandleToSensor.get(handle);
    383             SensorEvent t = null;
    384             synchronized (mSensorsEvents) {
    385                 t = mSensorsEvents.get(handle);
    386             }
    387 
    388             if (t == null) {
    389                 // This may happen if the client has unregistered and there are pending events in
    390                 // the queue waiting to be delivered. Ignore.
    391                 return;
    392             }
    393             // Copy from the values array.
    394             System.arraycopy(values, 0, t.values, 0, t.values.length);
    395             t.timestamp = timestamp;
    396             t.accuracy = inAccuracy;
    397             t.sensor = sensor;
    398 
    399             // call onAccuracyChanged() only if the value changes
    400             final int accuracy = mSensorAccuracies.get(handle);
    401             if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
    402                 mSensorAccuracies.put(handle, t.accuracy);
    403                 mListener.onAccuracyChanged(t.sensor, t.accuracy);
    404             }
    405             mListener.onSensorChanged(t);
    406         }
    407 
    408         @SuppressWarnings("unused")
    409         protected void dispatchFlushCompleteEvent(int handle) {
    410             if (mListener instanceof SensorEventListener2) {
    411                 final Sensor sensor = sHandleToSensor.get(handle);
    412                 ((SensorEventListener2)mListener).onFlushCompleted(sensor);
    413             }
    414             return;
    415         }
    416     }
    417 
    418     static final class TriggerEventQueue extends BaseEventQueue {
    419         private final TriggerEventListener mListener;
    420         private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
    421 
    422         public TriggerEventQueue(TriggerEventListener listener, Looper looper,
    423                 SystemSensorManager manager) {
    424             super(looper, manager);
    425             mListener = listener;
    426         }
    427 
    428         @Override
    429         public void addSensorEvent(Sensor sensor) {
    430             TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
    431                     mManager.mTargetSdkLevel));
    432             synchronized (mTriggerEvents) {
    433                 mTriggerEvents.put(sensor.getHandle(), t);
    434             }
    435         }
    436 
    437         @Override
    438         public void removeSensorEvent(Sensor sensor) {
    439             synchronized (mTriggerEvents) {
    440                 mTriggerEvents.delete(sensor.getHandle());
    441             }
    442         }
    443 
    444         // Called from native code.
    445         @SuppressWarnings("unused")
    446         @Override
    447         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
    448                 long timestamp) {
    449             final Sensor sensor = sHandleToSensor.get(handle);
    450             TriggerEvent t = null;
    451             synchronized (mTriggerEvents) {
    452                 t = mTriggerEvents.get(handle);
    453             }
    454             if (t == null) {
    455                 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
    456                 return;
    457             }
    458 
    459             // Copy from the values array.
    460             System.arraycopy(values, 0, t.values, 0, t.values.length);
    461             t.timestamp = timestamp;
    462             t.sensor = sensor;
    463 
    464             // A trigger sensor is auto disabled. So just clean up and don't call native
    465             // disable.
    466             mManager.cancelTriggerSensorImpl(mListener, sensor, false);
    467 
    468             mListener.onTrigger(t);
    469         }
    470 
    471         @SuppressWarnings("unused")
    472         protected void dispatchFlushCompleteEvent(int handle) {
    473         }
    474     }
    475 }
    476