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.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.os.Handler;
     24 import android.os.Looper;
     25 import android.os.MemoryFile;
     26 import android.os.MessageQueue;
     27 import android.util.Log;
     28 import android.util.SparseArray;
     29 import android.util.SparseBooleanArray;
     30 import android.util.SparseIntArray;
     31 import dalvik.system.CloseGuard;
     32 
     33 import com.android.internal.annotations.GuardedBy;
     34 
     35 import java.io.IOException;
     36 import java.io.UncheckedIOException;
     37 import java.lang.ref.WeakReference;
     38 import java.util.ArrayList;
     39 import java.util.HashMap;
     40 import java.util.List;
     41 import java.util.Map;
     42 
     43 
     44 /**
     45  * Sensor manager implementation that communicates with the built-in
     46  * system sensors.
     47  *
     48  * @hide
     49  */
     50 public class SystemSensorManager extends SensorManager {
     51     //TODO: disable extra logging before release
     52     private static final boolean DEBUG_DYNAMIC_SENSOR = true;
     53     private static final int MIN_DIRECT_CHANNEL_BUFFER_SIZE = 104;
     54     private static final int MAX_LISTENER_COUNT = 128;
     55 
     56     private static native void nativeClassInit();
     57     private static native long nativeCreate(String opPackageName);
     58     private static native boolean nativeGetSensorAtIndex(long nativeInstance,
     59             Sensor sensor, int index);
     60     private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
     61     private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
     62 
     63     private static native int nativeCreateDirectChannel(
     64             long nativeInstance, long size, int channelType, int fd, HardwareBuffer buffer);
     65     private static native void nativeDestroyDirectChannel(
     66             long nativeInstance, int channelHandle);
     67     private static native int nativeConfigDirectChannel(
     68             long nativeInstance, int channelHandle, int sensorHandle, int rate);
     69 
     70     private static native int nativeSetOperationParameter(
     71             long nativeInstance, int handle, int type, float[] floatValues, int[] intValues);
     72 
     73     private static final Object sLock = new Object();
     74     @GuardedBy("sLock")
     75     private static boolean sNativeClassInited = false;
     76     @GuardedBy("sLock")
     77     private static InjectEventQueue sInjectEventQueue = null;
     78 
     79     private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
     80     private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
     81     private boolean mDynamicSensorListDirty = true;
     82 
     83     private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
     84 
     85     // Listener list
     86     private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
     87             new HashMap<SensorEventListener, SensorEventQueue>();
     88     private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
     89             new HashMap<TriggerEventListener, TriggerEventQueue>();
     90 
     91     // Dynamic Sensor callbacks
     92     private HashMap<DynamicSensorCallback, Handler>
     93             mDynamicSensorCallbacks = new HashMap<>();
     94     private BroadcastReceiver mDynamicSensorBroadcastReceiver;
     95 
     96     // Looper associated with the context in which this instance was created.
     97     private final Looper mMainLooper;
     98     private final int mTargetSdkLevel;
     99     private final Context mContext;
    100     private final long mNativeInstance;
    101 
    102     /** {@hide} */
    103     public SystemSensorManager(Context context, Looper mainLooper) {
    104         synchronized(sLock) {
    105             if (!sNativeClassInited) {
    106                 sNativeClassInited = true;
    107                 nativeClassInit();
    108             }
    109         }
    110 
    111         mMainLooper = mainLooper;
    112         mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
    113         mContext = context;
    114         mNativeInstance = nativeCreate(context.getOpPackageName());
    115 
    116         // initialize the sensor list
    117         for (int index = 0;;++index) {
    118             Sensor sensor = new Sensor();
    119             if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
    120             mFullSensorsList.add(sensor);
    121             mHandleToSensor.put(sensor.getHandle(), sensor);
    122         }
    123     }
    124 
    125 
    126     /** @hide */
    127     @Override
    128     protected List<Sensor> getFullSensorList() {
    129         return mFullSensorsList;
    130     }
    131 
    132     /** @hide */
    133     @Override
    134     protected List<Sensor> getFullDynamicSensorList() {
    135         // only set up broadcast receiver if the application tries to find dynamic sensors or
    136         // explicitly register a DynamicSensorCallback
    137         setupDynamicSensorBroadcastReceiver();
    138         updateDynamicSensorList();
    139         return mFullDynamicSensorsList;
    140     }
    141 
    142     /** @hide */
    143     @Override
    144     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
    145             int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
    146         if (listener == null || sensor == null) {
    147             Log.e(TAG, "sensor or listener is null");
    148             return false;
    149         }
    150         // Trigger Sensors should use the requestTriggerSensor call.
    151         if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
    152             Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
    153             return false;
    154         }
    155         if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
    156             Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
    157             return false;
    158         }
    159         if (mSensorListeners.size() >= MAX_LISTENER_COUNT) {
    160             throw new IllegalStateException("register failed, " +
    161                 "the sensor listeners size has exceeded the maximum limit " +
    162                 MAX_LISTENER_COUNT);
    163         }
    164 
    165         // Invariants to preserve:
    166         // - one Looper per SensorEventListener
    167         // - one Looper per SensorEventQueue
    168         // We map SensorEventListener to a SensorEventQueue, which holds the looper
    169         synchronized (mSensorListeners) {
    170             SensorEventQueue queue = mSensorListeners.get(listener);
    171             if (queue == null) {
    172                 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
    173                 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
    174                     listener.getClass().getEnclosingClass().getName() :
    175                     listener.getClass().getName();
    176                 queue = new SensorEventQueue(listener, looper, this, fullClassName);
    177                 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
    178                     queue.dispose();
    179                     return false;
    180                 }
    181                 mSensorListeners.put(listener, queue);
    182                 return true;
    183             } else {
    184                 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
    185             }
    186         }
    187     }
    188 
    189     /** @hide */
    190     @Override
    191     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
    192         // Trigger Sensors should use the cancelTriggerSensor call.
    193         if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
    194             return;
    195         }
    196 
    197         synchronized (mSensorListeners) {
    198             SensorEventQueue queue = mSensorListeners.get(listener);
    199             if (queue != null) {
    200                 boolean result;
    201                 if (sensor == null) {
    202                     result = queue.removeAllSensors();
    203                 } else {
    204                     result = queue.removeSensor(sensor, true);
    205                 }
    206                 if (result && !queue.hasSensors()) {
    207                     mSensorListeners.remove(listener);
    208                     queue.dispose();
    209                 }
    210             }
    211         }
    212     }
    213 
    214     /** @hide */
    215     @Override
    216     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
    217         if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
    218 
    219         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
    220 
    221         if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
    222 
    223         if (mTriggerListeners.size() >= MAX_LISTENER_COUNT) {
    224             throw new IllegalStateException("request failed, " +
    225                     "the trigger listeners size has exceeded the maximum limit " +
    226                     MAX_LISTENER_COUNT);
    227         }
    228 
    229         synchronized (mTriggerListeners) {
    230             TriggerEventQueue queue = mTriggerListeners.get(listener);
    231             if (queue == null) {
    232                 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
    233                     listener.getClass().getEnclosingClass().getName() :
    234                     listener.getClass().getName();
    235                 queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName);
    236                 if (!queue.addSensor(sensor, 0, 0)) {
    237                     queue.dispose();
    238                     return false;
    239                 }
    240                 mTriggerListeners.put(listener, queue);
    241                 return true;
    242             } else {
    243                 return queue.addSensor(sensor, 0, 0);
    244             }
    245         }
    246     }
    247 
    248     /** @hide */
    249     @Override
    250     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
    251             boolean disable) {
    252         if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
    253             return false;
    254         }
    255         synchronized (mTriggerListeners) {
    256             TriggerEventQueue queue = mTriggerListeners.get(listener);
    257             if (queue != null) {
    258                 boolean result;
    259                 if (sensor == null) {
    260                     result = queue.removeAllSensors();
    261                 } else {
    262                     result = queue.removeSensor(sensor, disable);
    263                 }
    264                 if (result && !queue.hasSensors()) {
    265                     mTriggerListeners.remove(listener);
    266                     queue.dispose();
    267                 }
    268                 return result;
    269             }
    270             return false;
    271         }
    272     }
    273 
    274     protected boolean flushImpl(SensorEventListener listener) {
    275         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
    276 
    277         synchronized (mSensorListeners) {
    278             SensorEventQueue queue = mSensorListeners.get(listener);
    279             if (queue == null) {
    280                 return false;
    281             } else {
    282                 return (queue.flush() == 0);
    283             }
    284         }
    285     }
    286 
    287     protected boolean initDataInjectionImpl(boolean enable) {
    288         synchronized (sLock) {
    289             if (enable) {
    290                 boolean isDataInjectionModeEnabled = nativeIsDataInjectionEnabled(mNativeInstance);
    291                 // The HAL does not support injection OR SensorService hasn't been set in DI mode.
    292                 if (!isDataInjectionModeEnabled) {
    293                     Log.e(TAG, "Data Injection mode not enabled");
    294                     return false;
    295                 }
    296                 // Initialize a client for data_injection.
    297                 if (sInjectEventQueue == null) {
    298                     try {
    299                         sInjectEventQueue = new InjectEventQueue(
    300                                 mMainLooper, this, mContext.getPackageName());
    301                     } catch (RuntimeException e) {
    302                         Log.e(TAG, "Cannot create InjectEventQueue: " + e);
    303                     }
    304                 }
    305                 return sInjectEventQueue != null;
    306             } else {
    307                 // If data injection is being disabled clean up the native resources.
    308                 if (sInjectEventQueue != null) {
    309                     sInjectEventQueue.dispose();
    310                     sInjectEventQueue = null;
    311                 }
    312                 return true;
    313             }
    314         }
    315     }
    316 
    317     protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
    318             long timestamp) {
    319         synchronized (sLock) {
    320             if (sInjectEventQueue == null) {
    321                 Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
    322                 return false;
    323             }
    324             int ret = sInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
    325                                                          timestamp);
    326             // If there are any errors in data injection clean up the native resources.
    327             if (ret != 0) {
    328                 sInjectEventQueue.dispose();
    329                 sInjectEventQueue = null;
    330             }
    331             return ret == 0;
    332         }
    333     }
    334 
    335     private void cleanupSensorConnection(Sensor sensor) {
    336         mHandleToSensor.remove(sensor.getHandle());
    337 
    338         if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
    339             synchronized(mTriggerListeners) {
    340                 HashMap<TriggerEventListener, TriggerEventQueue> triggerListeners =
    341                     new HashMap<TriggerEventListener, TriggerEventQueue>(mTriggerListeners);
    342 
    343                 for (TriggerEventListener l: triggerListeners.keySet()) {
    344                     if (DEBUG_DYNAMIC_SENSOR){
    345                         Log.i(TAG, "removed trigger listener" + l.toString() +
    346                                    " due to sensor disconnection");
    347                     }
    348                     cancelTriggerSensorImpl(l, sensor, true);
    349                 }
    350             }
    351         } else {
    352             synchronized(mSensorListeners) {
    353                 HashMap<SensorEventListener, SensorEventQueue> sensorListeners =
    354                     new HashMap<SensorEventListener, SensorEventQueue>(mSensorListeners);
    355 
    356                 for (SensorEventListener l: sensorListeners.keySet()) {
    357                     if (DEBUG_DYNAMIC_SENSOR){
    358                         Log.i(TAG, "removed event listener" + l.toString() +
    359                                    " due to sensor disconnection");
    360                     }
    361                     unregisterListenerImpl(l, sensor);
    362                 }
    363             }
    364         }
    365     }
    366 
    367     private void updateDynamicSensorList() {
    368         synchronized(mFullDynamicSensorsList) {
    369             if (mDynamicSensorListDirty) {
    370                 List<Sensor> list = new ArrayList<>();
    371                 nativeGetDynamicSensors(mNativeInstance, list);
    372 
    373                 final List<Sensor> updatedList = new ArrayList<>();
    374                 final List<Sensor> addedList = new ArrayList<>();
    375                 final List<Sensor> removedList = new ArrayList<>();
    376 
    377                 boolean changed = diffSortedSensorList(
    378                         mFullDynamicSensorsList, list, updatedList, addedList, removedList);
    379 
    380                 if (changed) {
    381                     if (DEBUG_DYNAMIC_SENSOR) {
    382                         Log.i(TAG, "DYNS dynamic sensor list cached should be updated");
    383                     }
    384                     mFullDynamicSensorsList = updatedList;
    385 
    386                     for (Sensor s: addedList) {
    387                         mHandleToSensor.put(s.getHandle(), s);
    388                     }
    389 
    390                     Handler mainHandler = new Handler(mContext.getMainLooper());
    391 
    392                     for (Map.Entry<DynamicSensorCallback, Handler> entry :
    393                             mDynamicSensorCallbacks.entrySet()) {
    394                         final DynamicSensorCallback callback = entry.getKey();
    395                         Handler handler =
    396                                 entry.getValue() == null ? mainHandler : entry.getValue();
    397 
    398                         handler.post(new Runnable() {
    399                             @Override
    400                             public void run() {
    401                                 for (Sensor s: addedList) {
    402                                     callback.onDynamicSensorConnected(s);
    403                                 }
    404                                 for (Sensor s: removedList) {
    405                                     callback.onDynamicSensorDisconnected(s);
    406                                 }
    407                             }
    408                         });
    409                     }
    410 
    411                     for (Sensor s: removedList) {
    412                         cleanupSensorConnection(s);
    413                     }
    414                 }
    415 
    416                 mDynamicSensorListDirty = false;
    417             }
    418         }
    419     }
    420 
    421     private void setupDynamicSensorBroadcastReceiver() {
    422         if (mDynamicSensorBroadcastReceiver == null) {
    423             mDynamicSensorBroadcastReceiver = new BroadcastReceiver() {
    424                 @Override
    425                 public void onReceive(Context context, Intent intent) {
    426                     if (intent.getAction() == Intent.ACTION_DYNAMIC_SENSOR_CHANGED) {
    427                         if (DEBUG_DYNAMIC_SENSOR) {
    428                             Log.i(TAG, "DYNS received DYNAMIC_SENSOR_CHANED broadcast");
    429                         }
    430                         // Dynamic sensors probably changed
    431                         mDynamicSensorListDirty = true;
    432                         updateDynamicSensorList();
    433                     }
    434                 }
    435             };
    436 
    437             IntentFilter filter = new IntentFilter("dynamic_sensor_change");
    438             filter.addAction(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
    439             mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter);
    440         }
    441     }
    442 
    443     private void teardownDynamicSensorBroadcastReceiver() {
    444         mDynamicSensorCallbacks.clear();
    445         mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver);
    446         mDynamicSensorBroadcastReceiver = null;
    447     }
    448 
    449     /** @hide */
    450     protected void registerDynamicSensorCallbackImpl(
    451             DynamicSensorCallback callback, Handler handler) {
    452         if (DEBUG_DYNAMIC_SENSOR) {
    453             Log.i(TAG, "DYNS Register dynamic sensor callback");
    454         }
    455 
    456         if (callback == null) {
    457             throw new IllegalArgumentException("callback cannot be null");
    458         }
    459         if (mDynamicSensorCallbacks.containsKey(callback)) {
    460             // has been already registered, ignore
    461             return;
    462         }
    463 
    464         setupDynamicSensorBroadcastReceiver();
    465         mDynamicSensorCallbacks.put(callback, handler);
    466     }
    467 
    468     /** @hide */
    469     protected void unregisterDynamicSensorCallbackImpl(
    470             DynamicSensorCallback callback) {
    471         if (DEBUG_DYNAMIC_SENSOR) {
    472             Log.i(TAG, "Removing dynamic sensor listerner");
    473         }
    474         mDynamicSensorCallbacks.remove(callback);
    475     }
    476 
    477     /*
    478      * Find the difference of two List<Sensor> assuming List are sorted by handle of sensor,
    479      * assuming the input list is already sorted by handle. Inputs are ol and nl; outputs are
    480      * updated, added and removed. Any of the output lists can be null in case the result is not
    481      * interested.
    482      */
    483     private static boolean diffSortedSensorList(
    484             List<Sensor> oldList, List<Sensor> newList, List<Sensor> updated,
    485             List<Sensor> added, List<Sensor> removed) {
    486 
    487         boolean changed = false;
    488 
    489         int i = 0, j = 0;
    490         while (true) {
    491             if (j < oldList.size() && ( i >= newList.size() ||
    492                     newList.get(i).getHandle() > oldList.get(j).getHandle()) ) {
    493                 changed = true;
    494                 if (removed != null) {
    495                     removed.add(oldList.get(j));
    496                 }
    497                 ++j;
    498             } else if (i < newList.size() && ( j >= oldList.size() ||
    499                     newList.get(i).getHandle() < oldList.get(j).getHandle())) {
    500                 changed = true;
    501                 if (added != null) {
    502                     added.add(newList.get(i));
    503                 }
    504                 if (updated != null) {
    505                     updated.add(newList.get(i));
    506                 }
    507                 ++i;
    508             } else if (i < newList.size() && j < oldList.size() &&
    509                     newList.get(i).getHandle() == oldList.get(j).getHandle()) {
    510                 if (updated != null) {
    511                     updated.add(oldList.get(j));
    512                 }
    513                 ++i;
    514                 ++j;
    515             } else {
    516                 break;
    517             }
    518         }
    519         return changed;
    520     }
    521 
    522     /** @hide */
    523     protected int configureDirectChannelImpl(
    524             SensorDirectChannel channel, Sensor sensor, int rate) {
    525         if (!channel.isOpen()) {
    526             throw new IllegalStateException("channel is closed");
    527         }
    528 
    529         if (rate < SensorDirectChannel.RATE_STOP
    530                 || rate > SensorDirectChannel.RATE_VERY_FAST) {
    531             throw new IllegalArgumentException("rate parameter invalid");
    532         }
    533 
    534         if (sensor == null && rate != SensorDirectChannel.RATE_STOP) {
    535             // the stop all sensors case
    536             throw new IllegalArgumentException(
    537                     "when sensor is null, rate can only be DIRECT_RATE_STOP");
    538         }
    539 
    540         int sensorHandle = (sensor == null) ? -1 : sensor.getHandle();
    541 
    542         int ret = nativeConfigDirectChannel(
    543                 mNativeInstance, channel.getNativeHandle(), sensorHandle, rate);
    544 
    545         if (rate == SensorDirectChannel.RATE_STOP) {
    546             return (ret == 0) ? 1 : 0;
    547         } else {
    548             return (ret > 0) ? ret : 0;
    549         }
    550     }
    551 
    552     /** @hide */
    553     protected SensorDirectChannel createDirectChannelImpl(
    554             MemoryFile memoryFile, HardwareBuffer hardwareBuffer) {
    555         int id;
    556         int type;
    557         long size;
    558         if (memoryFile != null) {
    559             int fd;
    560             try {
    561                 fd = memoryFile.getFileDescriptor().getInt$();
    562             } catch (IOException e) {
    563                 throw new IllegalArgumentException("MemoryFile object is not valid");
    564             }
    565 
    566             if (memoryFile.length() < MIN_DIRECT_CHANNEL_BUFFER_SIZE) {
    567                 throw new IllegalArgumentException(
    568                         "Size of MemoryFile has to be greater than "
    569                         + MIN_DIRECT_CHANNEL_BUFFER_SIZE);
    570             }
    571 
    572             size = memoryFile.length();
    573             id = nativeCreateDirectChannel(
    574                     mNativeInstance, size, SensorDirectChannel.TYPE_MEMORY_FILE, fd, null);
    575             if (id <= 0) {
    576                 throw new UncheckedIOException(
    577                         new IOException("create MemoryFile direct channel failed " + id));
    578             }
    579             type = SensorDirectChannel.TYPE_MEMORY_FILE;
    580         } else if (hardwareBuffer != null) {
    581             if (hardwareBuffer.getFormat() != HardwareBuffer.BLOB) {
    582                 throw new IllegalArgumentException("Format of HardwareBuffer must be BLOB");
    583             }
    584             if (hardwareBuffer.getHeight() != 1) {
    585                 throw new IllegalArgumentException("Height of HardwareBuffer must be 1");
    586             }
    587             if (hardwareBuffer.getWidth() < MIN_DIRECT_CHANNEL_BUFFER_SIZE) {
    588                 throw new IllegalArgumentException(
    589                         "Width if HaradwareBuffer must be greater than "
    590                         + MIN_DIRECT_CHANNEL_BUFFER_SIZE);
    591             }
    592             if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_SENSOR_DIRECT_DATA) == 0) {
    593                 throw new IllegalArgumentException(
    594                         "HardwareBuffer must set usage flag USAGE_SENSOR_DIRECT_DATA");
    595             }
    596             size = hardwareBuffer.getWidth();
    597             id = nativeCreateDirectChannel(
    598                     mNativeInstance, size, SensorDirectChannel.TYPE_HARDWARE_BUFFER,
    599                     -1, hardwareBuffer);
    600             if (id <= 0) {
    601                 throw new UncheckedIOException(
    602                         new IOException("create HardwareBuffer direct channel failed " + id));
    603             }
    604             type = SensorDirectChannel.TYPE_HARDWARE_BUFFER;
    605         } else {
    606             throw new NullPointerException("shared memory object cannot be null");
    607         }
    608         return new SensorDirectChannel(this, id, type, size);
    609     }
    610 
    611     /** @hide */
    612     protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
    613         if (channel != null) {
    614             nativeDestroyDirectChannel(mNativeInstance, channel.getNativeHandle());
    615         }
    616     }
    617 
    618     /*
    619      * BaseEventQueue is the communication channel with the sensor service,
    620      * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
    621      * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case
    622      * where data is being injected into the sensor HAL through the sensor service. It is not
    623      * associated with any listener and there is one InjectEventQueue associated with a
    624      * SensorManager instance.
    625      */
    626     private static abstract class BaseEventQueue {
    627         private static native long nativeInitBaseEventQueue(long nativeManager,
    628                 WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
    629                 String packageName, int mode, String opPackageName);
    630         private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
    631                 int maxBatchReportLatencyUs);
    632         private static native int nativeDisableSensor(long eventQ, int handle);
    633         private static native void nativeDestroySensorEventQueue(long eventQ);
    634         private static native int nativeFlushSensor(long eventQ);
    635         private static native int nativeInjectSensorData(long eventQ, int handle,
    636                 float[] values,int accuracy, long timestamp);
    637 
    638         private long nSensorEventQueue;
    639         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
    640         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
    641         private final CloseGuard mCloseGuard = CloseGuard.get();
    642         protected final SystemSensorManager mManager;
    643 
    644         protected static final int OPERATING_MODE_NORMAL = 0;
    645         protected static final int OPERATING_MODE_DATA_INJECTION = 1;
    646 
    647         BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
    648             if (packageName == null) packageName = "";
    649             nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
    650                     new WeakReference<>(this), looper.getQueue(),
    651                     packageName, mode, manager.mContext.getOpPackageName());
    652             mCloseGuard.open("dispose");
    653             mManager = manager;
    654         }
    655 
    656         public void dispose() {
    657             dispose(false);
    658         }
    659 
    660         public boolean addSensor(
    661                 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
    662             // Check if already present.
    663             int handle = sensor.getHandle();
    664             if (mActiveSensors.get(handle)) return false;
    665 
    666             // Get ready to receive events before calling enable.
    667             mActiveSensors.put(handle, true);
    668             addSensorEvent(sensor);
    669             if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
    670                 // Try continuous mode if batching fails.
    671                 if (maxBatchReportLatencyUs == 0 ||
    672                     maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
    673                   removeSensor(sensor, false);
    674                   return false;
    675                 }
    676             }
    677             return true;
    678         }
    679 
    680         public boolean removeAllSensors() {
    681             for (int i=0 ; i<mActiveSensors.size(); i++) {
    682                 if (mActiveSensors.valueAt(i) == true) {
    683                     int handle = mActiveSensors.keyAt(i);
    684                     Sensor sensor = mManager.mHandleToSensor.get(handle);
    685                     if (sensor != null) {
    686                         disableSensor(sensor);
    687                         mActiveSensors.put(handle, false);
    688                         removeSensorEvent(sensor);
    689                     } else {
    690                         // sensor just disconnected -- just ignore.
    691                     }
    692                 }
    693             }
    694             return true;
    695         }
    696 
    697         public boolean removeSensor(Sensor sensor, boolean disable) {
    698             final int handle = sensor.getHandle();
    699             if (mActiveSensors.get(handle)) {
    700                 if (disable) disableSensor(sensor);
    701                 mActiveSensors.put(sensor.getHandle(), false);
    702                 removeSensorEvent(sensor);
    703                 return true;
    704             }
    705             return false;
    706         }
    707 
    708         public int flush() {
    709             if (nSensorEventQueue == 0) throw new NullPointerException();
    710             return nativeFlushSensor(nSensorEventQueue);
    711         }
    712 
    713         public boolean hasSensors() {
    714             // no more sensors are set
    715             return mActiveSensors.indexOfValue(true) >= 0;
    716         }
    717 
    718         @Override
    719         protected void finalize() throws Throwable {
    720             try {
    721                 dispose(true);
    722             } finally {
    723                 super.finalize();
    724             }
    725         }
    726 
    727         private void dispose(boolean finalized) {
    728             if (mCloseGuard != null) {
    729                 if (finalized) {
    730                     mCloseGuard.warnIfOpen();
    731                 }
    732                 mCloseGuard.close();
    733             }
    734             if (nSensorEventQueue != 0) {
    735                 nativeDestroySensorEventQueue(nSensorEventQueue);
    736                 nSensorEventQueue = 0;
    737             }
    738         }
    739 
    740         private int enableSensor(
    741                 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
    742             if (nSensorEventQueue == 0) throw new NullPointerException();
    743             if (sensor == null) throw new NullPointerException();
    744             return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
    745                     maxBatchReportLatencyUs);
    746         }
    747 
    748         protected int injectSensorDataBase(int handle, float[] values, int accuracy,
    749                                            long timestamp) {
    750             return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
    751         }
    752 
    753         private int disableSensor(Sensor sensor) {
    754             if (nSensorEventQueue == 0) throw new NullPointerException();
    755             if (sensor == null) throw new NullPointerException();
    756             return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
    757         }
    758         protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
    759                 long timestamp);
    760         protected abstract void dispatchFlushCompleteEvent(int handle);
    761 
    762         protected void dispatchAdditionalInfoEvent(
    763                 int handle, int type, int serial, float[] floatValues, int[] intValues) {
    764             // default implementation is do nothing
    765         }
    766 
    767         protected abstract void addSensorEvent(Sensor sensor);
    768         protected abstract void removeSensorEvent(Sensor sensor);
    769     }
    770 
    771     static final class SensorEventQueue extends BaseEventQueue {
    772         private final SensorEventListener mListener;
    773         private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
    774 
    775         public SensorEventQueue(SensorEventListener listener, Looper looper,
    776                 SystemSensorManager manager, String packageName) {
    777             super(looper, manager, OPERATING_MODE_NORMAL, packageName);
    778             mListener = listener;
    779         }
    780 
    781         @Override
    782         public void addSensorEvent(Sensor sensor) {
    783             SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
    784                     mManager.mTargetSdkLevel));
    785             synchronized (mSensorsEvents) {
    786                 mSensorsEvents.put(sensor.getHandle(), t);
    787             }
    788         }
    789 
    790         @Override
    791         public void removeSensorEvent(Sensor sensor) {
    792             synchronized (mSensorsEvents) {
    793                 mSensorsEvents.delete(sensor.getHandle());
    794             }
    795         }
    796 
    797         // Called from native code.
    798         @SuppressWarnings("unused")
    799         @Override
    800         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
    801                 long timestamp) {
    802             final Sensor sensor = mManager.mHandleToSensor.get(handle);
    803             if (sensor == null) {
    804                 // sensor disconnected
    805                 return;
    806             }
    807 
    808             SensorEvent t = null;
    809             synchronized (mSensorsEvents) {
    810                 t = mSensorsEvents.get(handle);
    811             }
    812 
    813             if (t == null) {
    814                 // This may happen if the client has unregistered and there are pending events in
    815                 // the queue waiting to be delivered. Ignore.
    816                 return;
    817             }
    818             // Copy from the values array.
    819             System.arraycopy(values, 0, t.values, 0, t.values.length);
    820             t.timestamp = timestamp;
    821             t.accuracy = inAccuracy;
    822             t.sensor = sensor;
    823 
    824             // call onAccuracyChanged() only if the value changes
    825             final int accuracy = mSensorAccuracies.get(handle);
    826             if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
    827                 mSensorAccuracies.put(handle, t.accuracy);
    828                 mListener.onAccuracyChanged(t.sensor, t.accuracy);
    829             }
    830             mListener.onSensorChanged(t);
    831         }
    832 
    833         // Called from native code.
    834         @SuppressWarnings("unused")
    835         @Override
    836         protected void dispatchFlushCompleteEvent(int handle) {
    837             if (mListener instanceof SensorEventListener2) {
    838                 final Sensor sensor = mManager.mHandleToSensor.get(handle);
    839                 if (sensor == null) {
    840                     // sensor disconnected
    841                     return;
    842                 }
    843                 ((SensorEventListener2)mListener).onFlushCompleted(sensor);
    844             }
    845             return;
    846         }
    847 
    848         // Called from native code.
    849         @SuppressWarnings("unused")
    850         @Override
    851         protected void dispatchAdditionalInfoEvent(
    852                 int handle, int type, int serial, float[] floatValues, int[] intValues) {
    853             if (mListener instanceof SensorEventCallback) {
    854                 final Sensor sensor = mManager.mHandleToSensor.get(handle);
    855                 if (sensor == null) {
    856                     // sensor disconnected
    857                     return;
    858                 }
    859                 SensorAdditionalInfo info =
    860                         new SensorAdditionalInfo(sensor, type, serial, intValues, floatValues);
    861                 ((SensorEventCallback)mListener).onSensorAdditionalInfo(info);
    862             }
    863         }
    864     }
    865 
    866     static final class TriggerEventQueue extends BaseEventQueue {
    867         private final TriggerEventListener mListener;
    868         private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
    869 
    870         public TriggerEventQueue(TriggerEventListener listener, Looper looper,
    871                 SystemSensorManager manager, String packageName) {
    872             super(looper, manager, OPERATING_MODE_NORMAL, packageName);
    873             mListener = listener;
    874         }
    875 
    876         @Override
    877         public void addSensorEvent(Sensor sensor) {
    878             TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
    879                     mManager.mTargetSdkLevel));
    880             synchronized (mTriggerEvents) {
    881                 mTriggerEvents.put(sensor.getHandle(), t);
    882             }
    883         }
    884 
    885         @Override
    886         public void removeSensorEvent(Sensor sensor) {
    887             synchronized (mTriggerEvents) {
    888                 mTriggerEvents.delete(sensor.getHandle());
    889             }
    890         }
    891 
    892         // Called from native code.
    893         @SuppressWarnings("unused")
    894         @Override
    895         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
    896                 long timestamp) {
    897             final Sensor sensor = mManager.mHandleToSensor.get(handle);
    898             if (sensor == null) {
    899                 // sensor disconnected
    900                 return;
    901             }
    902             TriggerEvent t = null;
    903             synchronized (mTriggerEvents) {
    904                 t = mTriggerEvents.get(handle);
    905             }
    906             if (t == null) {
    907                 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
    908                 return;
    909             }
    910 
    911             // Copy from the values array.
    912             System.arraycopy(values, 0, t.values, 0, t.values.length);
    913             t.timestamp = timestamp;
    914             t.sensor = sensor;
    915 
    916             // A trigger sensor is auto disabled. So just clean up and don't call native
    917             // disable.
    918             mManager.cancelTriggerSensorImpl(mListener, sensor, false);
    919 
    920             mListener.onTrigger(t);
    921         }
    922 
    923         @SuppressWarnings("unused")
    924         protected void dispatchFlushCompleteEvent(int handle) {
    925         }
    926     }
    927 
    928     final class InjectEventQueue extends BaseEventQueue {
    929         public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) {
    930             super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName);
    931         }
    932 
    933         int injectSensorData(int handle, float[] values,int accuracy, long timestamp) {
    934              return injectSensorDataBase(handle, values, accuracy, timestamp);
    935         }
    936 
    937         @SuppressWarnings("unused")
    938         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
    939                 long timestamp) {
    940         }
    941 
    942         @SuppressWarnings("unused")
    943         protected void dispatchFlushCompleteEvent(int handle) {
    944 
    945         }
    946 
    947         @SuppressWarnings("unused")
    948         protected void addSensorEvent(Sensor sensor) {
    949 
    950         }
    951 
    952         @SuppressWarnings("unused")
    953         protected void removeSensorEvent(Sensor sensor) {
    954 
    955         }
    956     }
    957 
    958     protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
    959         int handle = -1;
    960         if (parameter.sensor != null) handle = parameter.sensor.getHandle();
    961         return nativeSetOperationParameter(
    962                 mNativeInstance, handle, parameter.type, parameter.floatValues, parameter.intValues) == 0;
    963     }
    964 }
    965