blob: c6c999b8b63be968d499a93a0fb8d074b4053610 [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
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070019import android.content.Context;
Jeff Brown25157e42012-04-16 12:13:05 -070020import android.os.Handler;
Mathias Agopiandb772d82013-01-31 19:31:12 -080021import android.os.Looper;
22import android.os.MessageQueue;
Jeff Brown25157e42012-04-16 12:13:05 -070023import android.util.SparseArray;
24import android.util.SparseBooleanArray;
25import android.util.SparseIntArray;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080026import dalvik.system.CloseGuard;
27
28import java.util.ArrayList;
29import java.util.HashMap;
30import java.util.List;
Jeff Brown25157e42012-04-16 12:13:05 -070031
Jeff Brown25157e42012-04-16 12:13:05 -070032/**
33 * Sensor manager implementation that communicates with the built-in
34 * system sensors.
35 *
36 * @hide
37 */
38public class SystemSensorManager extends SensorManager {
Mathias Agopiandb772d82013-01-31 19:31:12 -080039 private static native void nativeClassInit();
40 private static native int nativeGetNextSensor(Sensor sensor, int next);
Jeff Brown25157e42012-04-16 12:13:05 -070041
Mathias Agopiandb772d82013-01-31 19:31:12 -080042 private static boolean sSensorModuleInitialized = false;
43 private static final Object sSensorModuleLock = new Object();
44 private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
45 private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
46
47 // Listener list
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080048 private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
49 new HashMap<SensorEventListener, SensorEventQueue>();
50 private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
51 new HashMap<TriggerEventListener, TriggerEventQueue>();
Jeff Brown25157e42012-04-16 12:13:05 -070052
Jeff Brown4481d9c2012-04-16 16:14:44 -070053 // Looper associated with the context in which this instance was created.
Mathias Agopiandb772d82013-01-31 19:31:12 -080054 private final Looper mMainLooper;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070055 private final int mTargetSdkLevel;
Jeff Brown25157e42012-04-16 12:13:05 -070056
Mathias Agopiandb772d82013-01-31 19:31:12 -080057 /** {@hide} */
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070058 public SystemSensorManager(Context context, Looper mainLooper) {
Jeff Brown25157e42012-04-16 12:13:05 -070059 mMainLooper = mainLooper;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070060 mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
Mathias Agopiandb772d82013-01-31 19:31:12 -080061 synchronized(sSensorModuleLock) {
Jeff Brown25157e42012-04-16 12:13:05 -070062 if (!sSensorModuleInitialized) {
63 sSensorModuleInitialized = true;
64
65 nativeClassInit();
66
67 // initialize the sensor list
Jeff Brown25157e42012-04-16 12:13:05 -070068 final ArrayList<Sensor> fullList = sFullSensorsList;
69 int i = 0;
70 do {
71 Sensor sensor = new Sensor();
Mathias Agopiandb772d82013-01-31 19:31:12 -080072 i = nativeGetNextSensor(sensor, i);
Jeff Brown25157e42012-04-16 12:13:05 -070073 if (i>=0) {
74 //Log.d(TAG, "found sensor: " + sensor.getName() +
75 // ", handle=" + sensor.getHandle());
76 fullList.add(sensor);
77 sHandleToSensor.append(sensor.getHandle(), sensor);
78 }
79 } while (i>0);
Jeff Brown25157e42012-04-16 12:13:05 -070080 }
81 }
82 }
83
Mathias Agopiandb772d82013-01-31 19:31:12 -080084
Jeff Brown25157e42012-04-16 12:13:05 -070085 /** @hide */
86 @Override
87 protected List<Sensor> getFullSensorList() {
88 return sFullSensorsList;
89 }
90
Jeff Brown25157e42012-04-16 12:13:05 -070091
92 /** @hide */
Jeff Brown4481d9c2012-04-16 16:14:44 -070093 @Override
Jeff Brown25157e42012-04-16 12:13:05 -070094 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
Mathias Agopiandb772d82013-01-31 19:31:12 -080095 int delay, Handler handler)
96 {
97 // Invariants to preserve:
98 // - one Looper per SensorEventListener
99 // - one Looper per SensorEventQueue
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800100 // We map SensorEventListener to a SensorEventQueue, which holds the looper
101 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
Mathias Agopiandb772d82013-01-31 19:31:12 -0800102
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800103 // Trigger Sensors should use the requestTriggerSensor call.
104 if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) return false;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800105
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800106 synchronized (mSensorListeners) {
107 SensorEventQueue queue = mSensorListeners.get(listener);
108 if (queue == null) {
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700109 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700110 queue = new SensorEventQueue(listener, looper, this);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800111 if (!queue.addSensor(sensor, delay)) {
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700112 queue.dispose();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800113 return false;
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700114 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800115 mSensorListeners.put(listener, queue);
116 return true;
117 } else {
118 return queue.addSensor(sensor, delay);
Jeff Brown25157e42012-04-16 12:13:05 -0700119 }
120 }
Jeff Brown25157e42012-04-16 12:13:05 -0700121 }
122
123 /** @hide */
124 @Override
125 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800126 // Trigger Sensors should use the cancelTriggerSensor call.
127 if (sensor != null && Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
128 return;
129 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800130
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800131 synchronized (mSensorListeners) {
132 SensorEventQueue queue = mSensorListeners.get(listener);
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700133 if (queue != null) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800134 boolean result;
135 if (sensor == null) {
136 result = queue.removeAllSensors();
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700137 } else {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800138 result = queue.removeSensor(sensor);
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700139 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800140 if (result && !queue.hasSensors()) {
141 mSensorListeners.remove(listener);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800142 queue.dispose();
Jeff Brown25157e42012-04-16 12:13:05 -0700143 }
144 }
145 }
146 }
147
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800148 /** @hide */
149 @Override
150 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
151 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
Jeff Brown25157e42012-04-16 12:13:05 -0700152
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800153 if (Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) return false;
154
155 synchronized (mTriggerListeners) {
156 TriggerEventQueue queue = mTriggerListeners.get(listener);
157 if (queue == null) {
158 queue = new TriggerEventQueue(listener, mMainLooper, this);
159 if (!queue.addSensor(sensor, 0)) {
160 queue.dispose();
161 return false;
162 }
163 mTriggerListeners.put(listener, queue);
164 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800165 } else {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800166 return queue.addSensor(sensor, 0);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800167 }
168 }
169 }
Jeff Brown25157e42012-04-16 12:13:05 -0700170
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800171 /** @hide */
172 @Override
173 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
174 if (sensor != null && Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) {
175 return false;
176 }
177 synchronized (mTriggerListeners) {
178 TriggerEventQueue queue = mTriggerListeners.get(listener);
179 if (queue != null) {
180 boolean result;
181 if (sensor == null) {
182 result = queue.removeAllSensors();
183 } else {
184 result = queue.removeSensor(sensor);
185 }
186 if (result && !queue.hasSensors()) {
187 mTriggerListeners.remove(listener);
188 queue.dispose();
189 }
190 return result;
191 }
192 return false;
193 }
194 }
195
Mathias Agopiandb772d82013-01-31 19:31:12 -0800196 /*
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800197 * BaseEventQueue is the communication channel with the sensor service,
198 * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
199 * the queues and the listeners.
Mathias Agopiandb772d82013-01-31 19:31:12 -0800200 */
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800201 private static abstract class BaseEventQueue {
202 private native int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700203
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800204 float[] scratch);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800205 private static native int nativeEnableSensor(int eventQ, int handle, int us);
206 private static native int nativeDisableSensor(int eventQ, int handle);
207 private static native void nativeDestroySensorEventQueue(int eventQ);
208 private int nSensorEventQueue;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800209 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800210 protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
211 protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
Mathias Agopiandb772d82013-01-31 19:31:12 -0800212 private final CloseGuard mCloseGuard = CloseGuard.get();
213 private final float[] mScratch = new float[16];
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700214 protected final SystemSensorManager mManager;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800215
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700216 BaseEventQueue(Looper looper, SystemSensorManager manager) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800217 nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800218 mCloseGuard.open("dispose");
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700219 mManager = manager;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800220 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800221
Mathias Agopiandb772d82013-01-31 19:31:12 -0800222 public void dispose() {
223 dispose(false);
224 }
225
226 public boolean addSensor(Sensor sensor, int delay) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800227 // Check if already present.
228 if (mActiveSensors.get(sensor.getHandle())) return false;
229
Mathias Agopiandb772d82013-01-31 19:31:12 -0800230 if (enableSensor(sensor, delay) == 0) {
231 mActiveSensors.put(sensor.getHandle(), true);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700232 addSensorEvent(sensor);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800233 return true;
234 }
235 return false;
236 }
237
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800238 public boolean removeAllSensors() {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800239 for (int i=0 ; i<mActiveSensors.size(); i++) {
240 if (mActiveSensors.valueAt(i) == true) {
241 int handle = mActiveSensors.keyAt(i);
242 Sensor sensor = sHandleToSensor.get(handle);
243 if (sensor != null) {
244 disableSensor(sensor);
245 mActiveSensors.put(handle, false);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700246 removeSensorEvent(sensor);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800247 } else {
248 // it should never happen -- just ignore.
249 }
250 }
251 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800252 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800253 }
254
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800255 public boolean removeSensor(Sensor sensor) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800256 final int handle = sensor.getHandle();
257 if (mActiveSensors.get(handle)) {
258 disableSensor(sensor);
259 mActiveSensors.put(sensor.getHandle(), false);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700260 removeSensorEvent(sensor);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800261 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800262 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800263 return false;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800264 }
265
266 public boolean hasSensors() {
267 // no more sensors are set
268 return mActiveSensors.indexOfValue(true) >= 0;
269 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800270
Mathias Agopiandb772d82013-01-31 19:31:12 -0800271 @Override
272 protected void finalize() throws Throwable {
273 try {
274 dispose(true);
275 } finally {
276 super.finalize();
277 }
278 }
279
280 private void dispose(boolean finalized) {
281 if (mCloseGuard != null) {
282 if (finalized) {
283 mCloseGuard.warnIfOpen();
284 }
285 mCloseGuard.close();
286 }
287 if (nSensorEventQueue != 0) {
288 nativeDestroySensorEventQueue(nSensorEventQueue);
289 nSensorEventQueue = 0;
290 }
291 }
292
293 private int enableSensor(Sensor sensor, int us) {
294 if (nSensorEventQueue == 0) throw new NullPointerException();
295 if (sensor == null) throw new NullPointerException();
296 return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us);
297 }
298 private int disableSensor(Sensor sensor) {
299 if (nSensorEventQueue == 0) throw new NullPointerException();
300 if (sensor == null) throw new NullPointerException();
301 return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
302 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800303 protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
304 long timestamp);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700305
306 protected abstract void addSensorEvent(Sensor sensor);
307 protected abstract void removeSensorEvent(Sensor sensor);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800308 }
309
310 static final class SensorEventQueue extends BaseEventQueue {
311 private final SensorEventListener mListener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700312 private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800313
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700314 public SensorEventQueue(SensorEventListener listener, Looper looper,
315 SystemSensorManager manager) {
316 super(looper, manager);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800317 mListener = listener;
318 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800319
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700320 public void addSensorEvent(Sensor sensor) {
321 SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
322 mManager.mTargetSdkLevel));
323 mSensorsEvents.put(sensor.getHandle(), t);
324 }
325
326 public void removeSensorEvent(Sensor sensor) {
327 mSensorsEvents.delete(sensor.getHandle());
328 }
329
Mathias Agopiandb772d82013-01-31 19:31:12 -0800330 // Called from native code.
331 @SuppressWarnings("unused")
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800332 @Override
333 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
334 long timestamp) {
335 final Sensor sensor = sHandleToSensor.get(handle);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700336 SensorEvent t = mSensorsEvents.get(handle);
337 // Copy from the values array.
338 System.arraycopy(values, 0, t.values, 0, t.values.length);
339 t.timestamp = timestamp;
340 t.accuracy = inAccuracy;
341 t.sensor = sensor;
342 switch (t.sensor.getType()) {
343 // Only report accuracy for sensors that support it.
344 case Sensor.TYPE_MAGNETIC_FIELD:
345 case Sensor.TYPE_ORIENTATION:
346 // call onAccuracyChanged() only if the value changes
347 final int accuracy = mSensorAccuracies.get(handle);
348 if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
349 mSensorAccuracies.put(handle, t.accuracy);
350 mListener.onAccuracyChanged(t.sensor, t.accuracy);
351 }
352 break;
353 default:
354 // For other sensors, just report the accuracy once
355 if (mFirstEvent.get(handle) == false) {
356 mFirstEvent.put(handle, true);
357 mListener.onAccuracyChanged(
358 t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
359 }
360 break;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800361 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700362 mListener.onSensorChanged(t);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800363 }
364 }
365
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800366 static final class TriggerEventQueue extends BaseEventQueue {
367 private final TriggerEventListener mListener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700368 private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
Mathias Agopiandb772d82013-01-31 19:31:12 -0800369
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800370 public TriggerEventQueue(TriggerEventListener listener, Looper looper,
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700371 SystemSensorManager manager) {
372 super(looper, manager);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800373 mListener = listener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700374 }
375
376 public void addSensorEvent(Sensor sensor) {
377 TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
378 mManager.mTargetSdkLevel));
379 mTriggerEvents.put(sensor.getHandle(), t);
380 }
381
382 public void removeSensorEvent(Sensor sensor) {
383 mTriggerEvents.delete(sensor.getHandle());
Mathias Agopiandb772d82013-01-31 19:31:12 -0800384 }
385
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800386 // Called from native code.
387 @SuppressWarnings("unused")
388 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700389 protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
390 long timestamp) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800391 final Sensor sensor = sHandleToSensor.get(handle);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700392 TriggerEvent t = mTriggerEvents.get(handle);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800393
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700394 // Copy from the values array.
395 System.arraycopy(values, 0, t.values, 0, t.values.length);
396 t.timestamp = timestamp;
397 t.sensor = sensor;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800398
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700399 // A trigger sensor should be auto disabled.
400 mManager.cancelTriggerSensorImpl(mListener, sensor);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800401
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700402 mListener.onTrigger(t);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800403 }
404 }
Jeff Brown25157e42012-04-16 12:13:05 -0700405}