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