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) == 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) == 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) != 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) != 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 int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
    226                 float[] scratch);
    227         private static native int nativeEnableSensor(int eventQ, int handle, int rateUs,
    228                 int maxBatchReportLatencyUs, int reservedFlags);
    229         private static native int nativeDisableSensor(int eventQ, int handle);
    230         private static native void nativeDestroySensorEventQueue(int eventQ);
    231         private static native int nativeFlushSensor(int eventQ);
    232         private int 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         public void addSensorEvent(Sensor sensor) {
    362             SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
    363                     mManager.mTargetSdkLevel));
    364             mSensorsEvents.put(sensor.getHandle(), t);
    365         }
    366 
    367         public void removeSensorEvent(Sensor sensor) {
    368             mSensorsEvents.delete(sensor.getHandle());
    369         }
    370 
    371         // Called from native code.
    372         @SuppressWarnings("unused")
    373         @Override
    374         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
    375                 long timestamp) {
    376             final Sensor sensor = sHandleToSensor.get(handle);
    377             SensorEvent t = mSensorsEvents.get(handle);
    378             if (t == null) {
    379                 Log.e(TAG, "Error: Sensor Event is null for Sensor: " + sensor);
    380                 return;
    381             }
    382             // Copy from the values array.
    383             System.arraycopy(values, 0, t.values, 0, t.values.length);
    384             t.timestamp = timestamp;
    385             t.accuracy = inAccuracy;
    386             t.sensor = sensor;
    387             switch (t.sensor.getType()) {
    388                 // Only report accuracy for sensors that support it.
    389                 case Sensor.TYPE_MAGNETIC_FIELD:
    390                 case Sensor.TYPE_ORIENTATION:
    391                     // call onAccuracyChanged() only if the value changes
    392                     final int accuracy = mSensorAccuracies.get(handle);
    393                     if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
    394                         mSensorAccuracies.put(handle, t.accuracy);
    395                         mListener.onAccuracyChanged(t.sensor, t.accuracy);
    396                     }
    397                     break;
    398                 default:
    399                     // For other sensors, just report the accuracy once
    400                     if (mFirstEvent.get(handle) == false) {
    401                         mFirstEvent.put(handle, true);
    402                         mListener.onAccuracyChanged(
    403                                 t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
    404                     }
    405                     break;
    406             }
    407             mListener.onSensorChanged(t);
    408         }
    409 
    410         @SuppressWarnings("unused")
    411         protected void dispatchFlushCompleteEvent(int handle) {
    412             if (mListener instanceof SensorEventListener2) {
    413                 final Sensor sensor = sHandleToSensor.get(handle);
    414                 ((SensorEventListener2)mListener).onFlushCompleted(sensor);
    415             }
    416             return;
    417         }
    418     }
    419 
    420     static final class TriggerEventQueue extends BaseEventQueue {
    421         private final TriggerEventListener mListener;
    422         private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
    423 
    424         public TriggerEventQueue(TriggerEventListener listener, Looper looper,
    425                 SystemSensorManager manager) {
    426             super(looper, manager);
    427             mListener = listener;
    428         }
    429 
    430         public void addSensorEvent(Sensor sensor) {
    431             TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
    432                     mManager.mTargetSdkLevel));
    433             mTriggerEvents.put(sensor.getHandle(), t);
    434         }
    435 
    436         public void removeSensorEvent(Sensor sensor) {
    437             mTriggerEvents.delete(sensor.getHandle());
    438         }
    439 
    440         // Called from native code.
    441         @SuppressWarnings("unused")
    442         @Override
    443         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
    444                 long timestamp) {
    445             final Sensor sensor = sHandleToSensor.get(handle);
    446             TriggerEvent t = mTriggerEvents.get(handle);
    447             if (t == null) {
    448                 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
    449                 return;
    450             }
    451 
    452             // Copy from the values array.
    453             System.arraycopy(values, 0, t.values, 0, t.values.length);
    454             t.timestamp = timestamp;
    455             t.sensor = sensor;
    456 
    457             // A trigger sensor is auto disabled. So just clean up and don't call native
    458             // disable.
    459             mManager.cancelTriggerSensorImpl(mListener, sensor, false);
    460 
    461             mListener.onTrigger(t);
    462         }
    463 
    464         @SuppressWarnings("unused")
    465         protected void dispatchFlushCompleteEvent(int handle) {
    466         }
    467     }
    468 }
    469