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