blob: 2fe8fb6f71ceddaddd53fd3223d498084279feef [file] [log] [blame]
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -07001 /*
Jeff Brown25157e42012-04-16 12:13:05 -07002 * 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
Aravind Akella18ebf732b2015-04-20 17:39:51 -070019import android.Manifest;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070020import android.content.Context;
Aravind Akella18ebf732b2015-04-20 17:39:51 -070021import android.content.pm.PackageManager;
Jeff Brown25157e42012-04-16 12:13:05 -070022import android.os.Handler;
Mathias Agopiandb772d82013-01-31 19:31:12 -080023import android.os.Looper;
24import android.os.MessageQueue;
Jaikumar Ganesh2e900892013-04-11 10:40:33 -070025import android.util.Log;
Jeff Brown25157e42012-04-16 12:13:05 -070026import android.util.SparseArray;
27import android.util.SparseBooleanArray;
28import android.util.SparseIntArray;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080029import dalvik.system.CloseGuard;
30
Jeff Brown3b4049e2015-04-17 15:22:27 -070031import java.lang.ref.WeakReference;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080032import java.util.ArrayList;
33import java.util.HashMap;
34import java.util.List;
Jeff Brown25157e42012-04-16 12:13:05 -070035
Jeff Brown25157e42012-04-16 12:13:05 -070036/**
37 * Sensor manager implementation that communicates with the built-in
38 * system sensors.
39 *
40 * @hide
41 */
42public class SystemSensorManager extends SensorManager {
Mathias Agopiandb772d82013-01-31 19:31:12 -080043 private static native void nativeClassInit();
Svet Ganovb9d71a62015-04-30 10:38:13 -070044 private static native long nativeCreate(String opPackageName);
Aravind Akella516e40e2015-07-01 16:54:24 -070045 private static native boolean nativeGetSensorAtIndex(long nativeInstance,
46 Sensor sensor, int index);
Aravind Akellad123b512015-06-29 12:35:51 -070047 private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
Jeff Brown25157e42012-04-16 12:13:05 -070048
Mathias Agopiandb772d82013-01-31 19:31:12 -080049 private static boolean sSensorModuleInitialized = false;
Aravind Akella18ebf732b2015-04-20 17:39:51 -070050 private static InjectEventQueue mInjectEventQueue = null;
Mathias Agopiandb772d82013-01-31 19:31:12 -080051
Svet Ganovb9d71a62015-04-30 10:38:13 -070052 private final Object mLock = new Object();
53
54 private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
55 private final SparseArray<Sensor> mHandleToSensor = new SparseArray<>();
56
Mathias Agopiandb772d82013-01-31 19:31:12 -080057 // Listener list
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080058 private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
59 new HashMap<SensorEventListener, SensorEventQueue>();
60 private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
61 new HashMap<TriggerEventListener, TriggerEventQueue>();
Jeff Brown25157e42012-04-16 12:13:05 -070062
Jeff Brown4481d9c2012-04-16 16:14:44 -070063 // Looper associated with the context in which this instance was created.
Mathias Agopiandb772d82013-01-31 19:31:12 -080064 private final Looper mMainLooper;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070065 private final int mTargetSdkLevel;
Svet Ganovb9d71a62015-04-30 10:38:13 -070066 private final Context mContext;
Svet Ganovb9d71a62015-04-30 10:38:13 -070067 private final long mNativeInstance;
Jeff Brown25157e42012-04-16 12:13:05 -070068
Mathias Agopiandb772d82013-01-31 19:31:12 -080069 /** {@hide} */
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070070 public SystemSensorManager(Context context, Looper mainLooper) {
Jeff Brown25157e42012-04-16 12:13:05 -070071 mMainLooper = mainLooper;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070072 mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
Svet Ganovb9d71a62015-04-30 10:38:13 -070073 mContext = context;
74 mNativeInstance = nativeCreate(context.getOpPackageName());
75
76 synchronized(mLock) {
Jeff Brown25157e42012-04-16 12:13:05 -070077 if (!sSensorModuleInitialized) {
78 sSensorModuleInitialized = true;
Jeff Brown25157e42012-04-16 12:13:05 -070079 nativeClassInit();
Jeff Brown25157e42012-04-16 12:13:05 -070080 }
Svet Ganovb9d71a62015-04-30 10:38:13 -070081
Aravind Akellaa05df452015-10-16 14:18:40 -070082 // initialize the sensor list
83 for (int index = 0;;++index) {
84 Sensor sensor = new Sensor();
85 if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
86 mFullSensorsList.add(sensor);
87 mHandleToSensor.append(sensor.getHandle(), sensor);
88 }
Aravind Akella516e40e2015-07-01 16:54:24 -070089 }
Jeff Brown25157e42012-04-16 12:13:05 -070090 }
91
Mathias Agopiandb772d82013-01-31 19:31:12 -080092
Jeff Brown25157e42012-04-16 12:13:05 -070093 /** @hide */
94 @Override
95 protected List<Sensor> getFullSensorList() {
Svet Ganovb9d71a62015-04-30 10:38:13 -070096 return mFullSensorsList;
Jeff Brown25157e42012-04-16 12:13:05 -070097 }
98
Jeff Brown25157e42012-04-16 12:13:05 -070099
100 /** @hide */
Jeff Brown4481d9c2012-04-16 16:14:44 -0700101 @Override
Jeff Brown25157e42012-04-16 12:13:05 -0700102 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700103 int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
104 if (listener == null || sensor == null) {
105 Log.e(TAG, "sensor or listener is null");
106 return false;
107 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700108 // Trigger Sensors should use the requestTriggerSensor call.
Aravind Akella27900352014-06-03 19:20:42 -0700109 if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700110 Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
111 return false;
112 }
113 if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
114 Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
115 return false;
116 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700117
Mathias Agopiandb772d82013-01-31 19:31:12 -0800118 // Invariants to preserve:
119 // - one Looper per SensorEventListener
120 // - one Looper per SensorEventQueue
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800121 // We map SensorEventListener to a SensorEventQueue, which holds the looper
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800122 synchronized (mSensorListeners) {
123 SensorEventQueue queue = mSensorListeners.get(listener);
124 if (queue == null) {
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700125 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
Aravind Akella11fce8e2015-07-09 14:11:45 -0700126 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
127 listener.getClass().getEnclosingClass().getName() :
128 listener.getClass().getName();
129 queue = new SensorEventQueue(listener, looper, this, fullClassName);
Aravind Akella88445992015-02-26 17:05:28 -0800130 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700131 queue.dispose();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800132 return false;
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700133 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800134 mSensorListeners.put(listener, queue);
135 return true;
136 } else {
Aravind Akella88445992015-02-26 17:05:28 -0800137 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
Jeff Brown25157e42012-04-16 12:13:05 -0700138 }
139 }
Jeff Brown25157e42012-04-16 12:13:05 -0700140 }
141
142 /** @hide */
143 @Override
144 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800145 // Trigger Sensors should use the cancelTriggerSensor call.
Aravind Akella27900352014-06-03 19:20:42 -0700146 if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800147 return;
148 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800149
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800150 synchronized (mSensorListeners) {
151 SensorEventQueue queue = mSensorListeners.get(listener);
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700152 if (queue != null) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800153 boolean result;
154 if (sensor == null) {
155 result = queue.removeAllSensors();
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700156 } else {
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700157 result = queue.removeSensor(sensor, true);
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700158 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800159 if (result && !queue.hasSensors()) {
160 mSensorListeners.remove(listener);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800161 queue.dispose();
Jeff Brown25157e42012-04-16 12:13:05 -0700162 }
163 }
164 }
165 }
166
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800167 /** @hide */
168 @Override
169 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
170 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
Jeff Brown25157e42012-04-16 12:13:05 -0700171
Aravind Akella11fce8e2015-07-09 14:11:45 -0700172 if (listener == null) throw new IllegalArgumentException("listener cannot be null");
173
Aravind Akella27900352014-06-03 19:20:42 -0700174 if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800175
176 synchronized (mTriggerListeners) {
177 TriggerEventQueue queue = mTriggerListeners.get(listener);
178 if (queue == null) {
Aravind Akella11fce8e2015-07-09 14:11:45 -0700179 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
180 listener.getClass().getEnclosingClass().getName() :
181 listener.getClass().getName();
182 queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName);
Aravind Akella88445992015-02-26 17:05:28 -0800183 if (!queue.addSensor(sensor, 0, 0)) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800184 queue.dispose();
185 return false;
186 }
187 mTriggerListeners.put(listener, queue);
188 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800189 } else {
Aravind Akella88445992015-02-26 17:05:28 -0800190 return queue.addSensor(sensor, 0, 0);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800191 }
192 }
193 }
Jeff Brown25157e42012-04-16 12:13:05 -0700194
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800195 /** @hide */
196 @Override
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700197 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
198 boolean disable) {
Aravind Akella27900352014-06-03 19:20:42 -0700199 if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800200 return false;
201 }
202 synchronized (mTriggerListeners) {
203 TriggerEventQueue queue = mTriggerListeners.get(listener);
204 if (queue != null) {
205 boolean result;
206 if (sensor == null) {
207 result = queue.removeAllSensors();
208 } else {
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700209 result = queue.removeSensor(sensor, disable);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800210 }
211 if (result && !queue.hasSensors()) {
212 mTriggerListeners.remove(listener);
213 queue.dispose();
214 }
215 return result;
216 }
217 return false;
218 }
219 }
220
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700221 protected boolean flushImpl(SensorEventListener listener) {
222 if (listener == null) throw new IllegalArgumentException("listener cannot be null");
Aravind Akellab4c76b12013-06-27 12:04:16 -0700223
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700224 synchronized (mSensorListeners) {
225 SensorEventQueue queue = mSensorListeners.get(listener);
226 if (queue == null) {
227 return false;
228 } else {
229 return (queue.flush() == 0);
230 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700231 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700232 }
233
Aravind Akellad123b512015-06-29 12:35:51 -0700234 protected boolean initDataInjectionImpl(boolean enable) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700235 synchronized (mLock) {
Aravind Akellad123b512015-06-29 12:35:51 -0700236 if (enable) {
237 boolean isDataInjectionModeEnabled = nativeIsDataInjectionEnabled(mNativeInstance);
238 // The HAL does not support injection OR SensorService hasn't been set in DI mode.
239 if (!isDataInjectionModeEnabled) {
240 Log.e(TAG, "Data Injection mode not enabled");
241 return false;
242 }
Aravind Akellad123b512015-06-29 12:35:51 -0700243 // Initialize a client for data_injection.
244 if (mInjectEventQueue == null) {
Aravind Akella11fce8e2015-07-09 14:11:45 -0700245 mInjectEventQueue = new InjectEventQueue(mMainLooper, this,
246 mContext.getPackageName());
Aravind Akellad123b512015-06-29 12:35:51 -0700247 }
248 } else {
249 // If data injection is being disabled clean up the native resources.
250 if (mInjectEventQueue != null) {
251 mInjectEventQueue.dispose();
252 mInjectEventQueue = null;
253 }
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700254 }
255 return true;
256 }
257 }
258
259 protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
260 long timestamp) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700261 synchronized (mLock) {
Aravind Akellad4cc5ec2015-07-06 14:56:10 -0700262 if (mInjectEventQueue == null) {
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700263 Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
264 return false;
265 }
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700266 int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
267 timestamp);
268 // If there are any errors in data injection clean up the native resources.
269 if (ret != 0) {
270 mInjectEventQueue.dispose();
271 mInjectEventQueue = null;
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700272 }
273 return ret == 0;
274 }
275 }
276
Mathias Agopiandb772d82013-01-31 19:31:12 -0800277 /*
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800278 * BaseEventQueue is the communication channel with the sensor service,
279 * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700280 * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case
281 * where data is being injected into the sensor HAL through the sensor service. It is not
282 * associated with any listener and there is one InjectEventQueue associated with a
283 * SensorManager instance.
Mathias Agopiandb772d82013-01-31 19:31:12 -0800284 */
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800285 private static abstract class BaseEventQueue {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700286 private static native long nativeInitBaseEventQueue(long nativeManager,
287 WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch,
288 String packageName, int mode, String opPackageName);
Ashok Bhat4838e332014-01-03 14:37:19 +0000289 private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
Aravind Akella88445992015-02-26 17:05:28 -0800290 int maxBatchReportLatencyUs);
Ashok Bhat4838e332014-01-03 14:37:19 +0000291 private static native int nativeDisableSensor(long eventQ, int handle);
292 private static native void nativeDestroySensorEventQueue(long eventQ);
293 private static native int nativeFlushSensor(long eventQ);
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700294 private static native int nativeInjectSensorData(long eventQ, int handle,
Svet Ganovb9d71a62015-04-30 10:38:13 -0700295 float[] values,int accuracy, long timestamp);
296
Ashok Bhat4838e332014-01-03 14:37:19 +0000297 private long nSensorEventQueue;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800298 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800299 protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
300 protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
Mathias Agopiandb772d82013-01-31 19:31:12 -0800301 private final CloseGuard mCloseGuard = CloseGuard.get();
302 private final float[] mScratch = new float[16];
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700303 protected final SystemSensorManager mManager;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800304
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700305 protected static final int OPERATING_MODE_NORMAL = 0;
306 protected static final int OPERATING_MODE_DATA_INJECTION = 1;
307
Aravind Akella11fce8e2015-07-09 14:11:45 -0700308 BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
309 if (packageName == null) packageName = "";
Svet Ganovb9d71a62015-04-30 10:38:13 -0700310 nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
311 new WeakReference<>(this), looper.getQueue(), mScratch,
Aravind Akella11fce8e2015-07-09 14:11:45 -0700312 packageName, mode, manager.mContext.getOpPackageName());
Mathias Agopiandb772d82013-01-31 19:31:12 -0800313 mCloseGuard.open("dispose");
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700314 mManager = manager;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800315 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800316
Mathias Agopiandb772d82013-01-31 19:31:12 -0800317 public void dispose() {
318 dispose(false);
319 }
320
Aravind Akellab4c76b12013-06-27 12:04:16 -0700321 public boolean addSensor(
Aravind Akella88445992015-02-26 17:05:28 -0800322 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800323 // Check if already present.
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700324 int handle = sensor.getHandle();
325 if (mActiveSensors.get(handle)) return false;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800326
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700327 // Get ready to receive events before calling enable.
328 mActiveSensors.put(handle, true);
329 addSensorEvent(sensor);
Aravind Akella88445992015-02-26 17:05:28 -0800330 if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
Aravind Akellab4c76b12013-06-27 12:04:16 -0700331 // Try continuous mode if batching fails.
332 if (maxBatchReportLatencyUs == 0 ||
Aravind Akella88445992015-02-26 17:05:28 -0800333 maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
Aravind Akellab4c76b12013-06-27 12:04:16 -0700334 removeSensor(sensor, false);
335 return false;
336 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800337 }
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700338 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800339 }
340
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800341 public boolean removeAllSensors() {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800342 for (int i=0 ; i<mActiveSensors.size(); i++) {
343 if (mActiveSensors.valueAt(i) == true) {
344 int handle = mActiveSensors.keyAt(i);
Svet Ganovb9d71a62015-04-30 10:38:13 -0700345 Sensor sensor = mManager.mHandleToSensor.get(handle);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800346 if (sensor != null) {
347 disableSensor(sensor);
348 mActiveSensors.put(handle, false);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700349 removeSensorEvent(sensor);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800350 } else {
351 // it should never happen -- just ignore.
352 }
353 }
354 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800355 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800356 }
357
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700358 public boolean removeSensor(Sensor sensor, boolean disable) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800359 final int handle = sensor.getHandle();
360 if (mActiveSensors.get(handle)) {
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700361 if (disable) disableSensor(sensor);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800362 mActiveSensors.put(sensor.getHandle(), false);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700363 removeSensorEvent(sensor);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800364 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800365 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800366 return false;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800367 }
368
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700369 public int flush() {
Aravind Akellab4c76b12013-06-27 12:04:16 -0700370 if (nSensorEventQueue == 0) throw new NullPointerException();
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700371 return nativeFlushSensor(nSensorEventQueue);
Aravind Akellab4c76b12013-06-27 12:04:16 -0700372 }
373
Mathias Agopiandb772d82013-01-31 19:31:12 -0800374 public boolean hasSensors() {
375 // no more sensors are set
376 return mActiveSensors.indexOfValue(true) >= 0;
377 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800378
Mathias Agopiandb772d82013-01-31 19:31:12 -0800379 @Override
380 protected void finalize() throws Throwable {
381 try {
382 dispose(true);
383 } finally {
384 super.finalize();
385 }
386 }
387
388 private void dispose(boolean finalized) {
389 if (mCloseGuard != null) {
390 if (finalized) {
391 mCloseGuard.warnIfOpen();
392 }
393 mCloseGuard.close();
394 }
395 if (nSensorEventQueue != 0) {
396 nativeDestroySensorEventQueue(nSensorEventQueue);
397 nSensorEventQueue = 0;
398 }
399 }
400
Aravind Akellab4c76b12013-06-27 12:04:16 -0700401 private int enableSensor(
Aravind Akella88445992015-02-26 17:05:28 -0800402 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800403 if (nSensorEventQueue == 0) throw new NullPointerException();
404 if (sensor == null) throw new NullPointerException();
Aravind Akellab4c76b12013-06-27 12:04:16 -0700405 return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
Aravind Akella88445992015-02-26 17:05:28 -0800406 maxBatchReportLatencyUs);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800407 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700408
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700409 protected int injectSensorDataBase(int handle, float[] values, int accuracy,
410 long timestamp) {
411 return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
412 }
413
Mathias Agopiandb772d82013-01-31 19:31:12 -0800414 private int disableSensor(Sensor sensor) {
415 if (nSensorEventQueue == 0) throw new NullPointerException();
416 if (sensor == null) throw new NullPointerException();
417 return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
418 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800419 protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
420 long timestamp);
Aravind Akellab4c76b12013-06-27 12:04:16 -0700421 protected abstract void dispatchFlushCompleteEvent(int handle);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700422
423 protected abstract void addSensorEvent(Sensor sensor);
424 protected abstract void removeSensorEvent(Sensor sensor);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800425 }
426
427 static final class SensorEventQueue extends BaseEventQueue {
428 private final SensorEventListener mListener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700429 private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800430
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700431 public SensorEventQueue(SensorEventListener listener, Looper looper,
Aravind Akella11fce8e2015-07-09 14:11:45 -0700432 SystemSensorManager manager, String packageName) {
433 super(looper, manager, OPERATING_MODE_NORMAL, packageName);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800434 mListener = listener;
435 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800436
Aravind Akella31d14ce2013-10-22 20:04:22 -0700437 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700438 public void addSensorEvent(Sensor sensor) {
439 SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
440 mManager.mTargetSdkLevel));
Aravind Akella31d14ce2013-10-22 20:04:22 -0700441 synchronized (mSensorsEvents) {
442 mSensorsEvents.put(sensor.getHandle(), t);
443 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700444 }
445
Aravind Akella31d14ce2013-10-22 20:04:22 -0700446 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700447 public void removeSensorEvent(Sensor sensor) {
Aravind Akella31d14ce2013-10-22 20:04:22 -0700448 synchronized (mSensorsEvents) {
449 mSensorsEvents.delete(sensor.getHandle());
450 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700451 }
452
Mathias Agopiandb772d82013-01-31 19:31:12 -0800453 // Called from native code.
454 @SuppressWarnings("unused")
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800455 @Override
456 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
457 long timestamp) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700458 final Sensor sensor = mManager.mHandleToSensor.get(handle);
Aravind Akella31d14ce2013-10-22 20:04:22 -0700459 SensorEvent t = null;
460 synchronized (mSensorsEvents) {
461 t = mSensorsEvents.get(handle);
462 }
463
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700464 if (t == null) {
Aravind Akella31d14ce2013-10-22 20:04:22 -0700465 // This may happen if the client has unregistered and there are pending events in
466 // the queue waiting to be delivered. Ignore.
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700467 return;
468 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700469 // Copy from the values array.
470 System.arraycopy(values, 0, t.values, 0, t.values.length);
471 t.timestamp = timestamp;
472 t.accuracy = inAccuracy;
473 t.sensor = sensor;
Etienne Le Grandaf805102014-05-16 12:21:41 -0700474
475 // call onAccuracyChanged() only if the value changes
476 final int accuracy = mSensorAccuracies.get(handle);
477 if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
478 mSensorAccuracies.put(handle, t.accuracy);
479 mListener.onAccuracyChanged(t.sensor, t.accuracy);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800480 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700481 mListener.onSensorChanged(t);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800482 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700483
484 @SuppressWarnings("unused")
485 protected void dispatchFlushCompleteEvent(int handle) {
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700486 if (mListener instanceof SensorEventListener2) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700487 final Sensor sensor = mManager.mHandleToSensor.get(handle);
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700488 ((SensorEventListener2)mListener).onFlushCompleted(sensor);
Aravind Akellab4c76b12013-06-27 12:04:16 -0700489 }
490 return;
491 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800492 }
493
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800494 static final class TriggerEventQueue extends BaseEventQueue {
495 private final TriggerEventListener mListener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700496 private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
Mathias Agopiandb772d82013-01-31 19:31:12 -0800497
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800498 public TriggerEventQueue(TriggerEventListener listener, Looper looper,
Aravind Akella11fce8e2015-07-09 14:11:45 -0700499 SystemSensorManager manager, String packageName) {
500 super(looper, manager, OPERATING_MODE_NORMAL, packageName);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800501 mListener = listener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700502 }
503
Aravind Akella31d14ce2013-10-22 20:04:22 -0700504 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700505 public void addSensorEvent(Sensor sensor) {
506 TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
507 mManager.mTargetSdkLevel));
Aravind Akella31d14ce2013-10-22 20:04:22 -0700508 synchronized (mTriggerEvents) {
509 mTriggerEvents.put(sensor.getHandle(), t);
510 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700511 }
512
Aravind Akella31d14ce2013-10-22 20:04:22 -0700513 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700514 public void removeSensorEvent(Sensor sensor) {
Aravind Akella31d14ce2013-10-22 20:04:22 -0700515 synchronized (mTriggerEvents) {
516 mTriggerEvents.delete(sensor.getHandle());
517 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800518 }
519
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800520 // Called from native code.
521 @SuppressWarnings("unused")
522 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700523 protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
524 long timestamp) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700525 final Sensor sensor = mManager.mHandleToSensor.get(handle);
Aravind Akella31d14ce2013-10-22 20:04:22 -0700526 TriggerEvent t = null;
527 synchronized (mTriggerEvents) {
528 t = mTriggerEvents.get(handle);
529 }
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700530 if (t == null) {
531 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
532 return;
533 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800534
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700535 // Copy from the values array.
536 System.arraycopy(values, 0, t.values, 0, t.values.length);
537 t.timestamp = timestamp;
538 t.sensor = sensor;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800539
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700540 // A trigger sensor is auto disabled. So just clean up and don't call native
541 // disable.
542 mManager.cancelTriggerSensorImpl(mListener, sensor, false);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800543
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700544 mListener.onTrigger(t);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800545 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700546
547 @SuppressWarnings("unused")
548 protected void dispatchFlushCompleteEvent(int handle) {
549 }
550 }
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700551
Svet Ganovb9d71a62015-04-30 10:38:13 -0700552 final class InjectEventQueue extends BaseEventQueue {
Aravind Akella11fce8e2015-07-09 14:11:45 -0700553 public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) {
554 super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName);
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700555 }
556
557 int injectSensorData(int handle, float[] values,int accuracy, long timestamp) {
558 return injectSensorDataBase(handle, values, accuracy, timestamp);
559 }
560
561 @SuppressWarnings("unused")
562 protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
563 long timestamp) {
564 }
565
566 @SuppressWarnings("unused")
567 protected void dispatchFlushCompleteEvent(int handle) {
568
569 }
570
571 @SuppressWarnings("unused")
572 protected void addSensorEvent(Sensor sensor) {
573
574 }
575
576 @SuppressWarnings("unused")
577 protected void removeSensorEvent(Sensor sensor) {
578
579 }
580 }
Jeff Brown25157e42012-04-16 12:13:05 -0700581}