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