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.Manifest;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
25import android.os.Handler;
26import android.os.Looper;
27import android.os.MessageQueue;
28import android.util.Log;
29import android.util.SparseArray;
30import android.util.SparseBooleanArray;
31import android.util.SparseIntArray;
32import dalvik.system.CloseGuard;
33
34import com.android.internal.annotations.GuardedBy;
35
36import java.lang.ref.WeakReference;
37import java.util.ArrayList;
38import java.util.HashMap;
39import java.util.List;
40import java.util.Map;
41
42
43/**
44 * Sensor manager implementation that communicates with the built-in
45 * system sensors.
46 *
47 * @hide
48 */
49public class SystemSensorManager extends SensorManager {
50    //TODO: disable extra logging before release
51    private static boolean DEBUG_DYNAMIC_SENSOR = true;
52
53    private static native void nativeClassInit();
54    private static native long nativeCreate(String opPackageName);
55    private static native boolean nativeGetSensorAtIndex(long nativeInstance,
56            Sensor sensor, int index);
57    private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
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} */
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
115    protected List<Sensor> getFullSensorList() {
116        return mFullSensorsList;
117    }
118
119    /** @hide */
120    @Override
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
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
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
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
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
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
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
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
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
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
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
408    private void teardownDynamicSensorBroadcastReceiver() {
409        mDynamicSensorCallbacks.clear();
410        mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver);
411        mDynamicSensorBroadcastReceiver = null;
412    }
413
414    /** @hide */
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 */
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     */
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 {
496        private static native long nativeInitBaseEventQueue(long nativeManager,
497                WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
498                String packageName, int mode, String opPackageName);
499        private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
500                int maxBatchReportLatencyUs);
501        private static native int nativeDisableSensor(long eventQ, int handle);
502        private static native void nativeDestroySensorEventQueue(long eventQ);
503        private static native int nativeFlushSensor(long eventQ);
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
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
525        public void dispose() {
526            dispose(false);
527        }
528
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
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
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
577        public int flush() {
578            if (nSensorEventQueue == 0) throw new NullPointerException();
579            return nativeFlushSensor(nSensorEventQueue);
580        }
581
582        public boolean hasSensors() {
583            // no more sensors are set
584            return mActiveSensors.indexOfValue(true) >= 0;
585        }
586
587        @Override
588        protected void finalize() throws Throwable {
589            try {
590                dispose(true);
591            } finally {
592                super.finalize();
593            }
594        }
595
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
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
617        protected int injectSensorDataBase(int handle, float[] values, int accuracy,
618                                           long timestamp) {
619            return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
620        }
621
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        }
627        protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
628                long timestamp);
629        protected abstract void dispatchFlushCompleteEvent(int handle);
630
631        protected void dispatchAdditionalInfoEvent(
632                int handle, int type, int serial, float[] floatValues, int[] intValues) {
633            // default implementation is do nothing
634        }
635
636        protected abstract void addSensorEvent(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
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
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
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
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
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
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
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
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
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
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")
793        protected void dispatchFlushCompleteEvent(int handle) {
794        }
795    }
796
797    final class InjectEventQueue extends BaseEventQueue {
798        public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) {
799            super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName);
800        }
801
802        int injectSensorData(int handle, float[] values,int accuracy, long timestamp) {
803             return injectSensorDataBase(handle, values, accuracy, timestamp);
804        }
805
806        @SuppressWarnings("unused")
807        protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
808                long timestamp) {
809        }
810
811        @SuppressWarnings("unused")
812        protected void dispatchFlushCompleteEvent(int handle) {
813
814        }
815
816        @SuppressWarnings("unused")
817        protected void addSensorEvent(Sensor sensor) {
818
819        }
820
821        @SuppressWarnings("unused")
822        protected void removeSensorEvent(Sensor sensor) {
823
824        }
825    }
826}
827