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