blob: 259ca032918b7eef4cda0a12d89e92d68f5ce5eb [file] [log] [blame]
Peng Xufb1c9412016-03-29 21:50:43 -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;
Peng Xua35b5532016-01-20 00:05:45 -080020import android.content.BroadcastReceiver;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070021import android.content.Context;
Peng Xua35b5532016-01-20 00:05:45 -080022import android.content.Intent;
23import android.content.IntentFilter;
Aravind Akella18ebf732b2015-04-20 17:39:51 -070024import android.content.pm.PackageManager;
Jeff Brown25157e42012-04-16 12:13:05 -070025import android.os.Handler;
Mathias Agopiandb772d82013-01-31 19:31:12 -080026import android.os.Looper;
27import android.os.MessageQueue;
Jaikumar Ganesh2e900892013-04-11 10:40:33 -070028import android.util.Log;
Jeff Brown25157e42012-04-16 12:13:05 -070029import android.util.SparseArray;
30import android.util.SparseBooleanArray;
31import android.util.SparseIntArray;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080032import dalvik.system.CloseGuard;
33
Peng Xu4a4baef2016-03-16 16:56:39 -070034import com.android.internal.annotations.GuardedBy;
35
Jeff Brown3b4049e2015-04-17 15:22:27 -070036import java.lang.ref.WeakReference;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080037import java.util.ArrayList;
38import java.util.HashMap;
39import java.util.List;
Peng Xua35b5532016-01-20 00:05:45 -080040import java.util.Map;
Jeff Brown25157e42012-04-16 12:13:05 -070041
Peng Xu4a4baef2016-03-16 16:56:39 -070042
Jeff Brown25157e42012-04-16 12:13:05 -070043/**
44 * Sensor manager implementation that communicates with the built-in
45 * system sensors.
46 *
47 * @hide
48 */
49public class SystemSensorManager extends SensorManager {
Peng Xua35b5532016-01-20 00:05:45 -080050 //TODO: disable extra logging before release
51 private static boolean DEBUG_DYNAMIC_SENSOR = true;
52
Mathias Agopiandb772d82013-01-31 19:31:12 -080053 private static native void nativeClassInit();
Svet Ganovb9d71a62015-04-30 10:38:13 -070054 private static native long nativeCreate(String opPackageName);
Aravind Akella516e40e2015-07-01 16:54:24 -070055 private static native boolean nativeGetSensorAtIndex(long nativeInstance,
56 Sensor sensor, int index);
Peng Xua35b5532016-01-20 00:05:45 -080057 private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
Aravind Akellad123b512015-06-29 12:35:51 -070058 private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
Jeff Brown25157e42012-04-16 12:13:05 -070059
Peng Xuaa957272016-03-15 18:16:45 -070060 private static final Object sLock = new Object();
Peng Xu4a4baef2016-03-16 16:56:39 -070061 @GuardedBy("sLock")
62 private static boolean sNativeClassInited = false;
63 @GuardedBy("sLock")
Peng Xuaa957272016-03-15 18:16:45 -070064 private static InjectEventQueue sInjectEventQueue = null;
Svet Ganovb9d71a62015-04-30 10:38:13 -070065
66 private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
Peng Xua35b5532016-01-20 00:05:45 -080067 private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
68 private boolean mDynamicSensorListDirty = true;
69
70 private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
Svet Ganovb9d71a62015-04-30 10:38:13 -070071
Mathias Agopiandb772d82013-01-31 19:31:12 -080072 // Listener list
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080073 private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
74 new HashMap<SensorEventListener, SensorEventQueue>();
75 private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
76 new HashMap<TriggerEventListener, TriggerEventQueue>();
Jeff Brown25157e42012-04-16 12:13:05 -070077
Peng Xua35b5532016-01-20 00:05:45 -080078 // Dynamic Sensor callbacks
Peng Xufb1c9412016-03-29 21:50:43 -070079 private HashMap<DynamicSensorCallback, Handler>
Peng Xua35b5532016-01-20 00:05:45 -080080 mDynamicSensorCallbacks = new HashMap<>();
81 private BroadcastReceiver mDynamicSensorBroadcastReceiver;
82
Jeff Brown4481d9c2012-04-16 16:14:44 -070083 // Looper associated with the context in which this instance was created.
Mathias Agopiandb772d82013-01-31 19:31:12 -080084 private final Looper mMainLooper;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070085 private final int mTargetSdkLevel;
Svet Ganovb9d71a62015-04-30 10:38:13 -070086 private final Context mContext;
Svet Ganovb9d71a62015-04-30 10:38:13 -070087 private final long mNativeInstance;
Jeff Brown25157e42012-04-16 12:13:05 -070088
Mathias Agopiandb772d82013-01-31 19:31:12 -080089 /** {@hide} */
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070090 public SystemSensorManager(Context context, Looper mainLooper) {
Peng Xuaa957272016-03-15 18:16:45 -070091 synchronized(sLock) {
Peng Xu4a4baef2016-03-16 16:56:39 -070092 if (!sNativeClassInited) {
93 sNativeClassInited = true;
Peng Xuaa957272016-03-15 18:16:45 -070094 nativeClassInit();
95 }
96 }
97
Jeff Brown25157e42012-04-16 12:13:05 -070098 mMainLooper = mainLooper;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -070099 mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
Svet Ganovb9d71a62015-04-30 10:38:13 -0700100 mContext = context;
101 mNativeInstance = nativeCreate(context.getOpPackageName());
102
Peng Xuaa957272016-03-15 18:16:45 -0700103 // 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);
Aravind Akella516e40e2015-07-01 16:54:24 -0700109 }
Jeff Brown25157e42012-04-16 12:13:05 -0700110 }
111
Mathias Agopiandb772d82013-01-31 19:31:12 -0800112
Jeff Brown25157e42012-04-16 12:13:05 -0700113 /** @hide */
114 @Override
115 protected List<Sensor> getFullSensorList() {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700116 return mFullSensorsList;
Jeff Brown25157e42012-04-16 12:13:05 -0700117 }
118
Peng Xua35b5532016-01-20 00:05:45 -0800119 /** @hide */
120 @Override
121 protected List<Sensor> getFullDynamicSensorList() {
122 // only set up broadcast receiver if the application tries to find dynamic sensors or
Peng Xufb1c9412016-03-29 21:50:43 -0700123 // explicitly register a DynamicSensorCallback
Peng Xua35b5532016-01-20 00:05:45 -0800124 setupDynamicSensorBroadcastReceiver();
125 updateDynamicSensorList();
126 return mFullDynamicSensorsList;
127 }
Jeff Brown25157e42012-04-16 12:13:05 -0700128
129 /** @hide */
Jeff Brown4481d9c2012-04-16 16:14:44 -0700130 @Override
Jeff Brown25157e42012-04-16 12:13:05 -0700131 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700132 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 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700137 // Trigger Sensors should use the requestTriggerSensor call.
Aravind Akella27900352014-06-03 19:20:42 -0700138 if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700139 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 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700146
Mathias Agopiandb772d82013-01-31 19:31:12 -0800147 // Invariants to preserve:
148 // - one Looper per SensorEventListener
149 // - one Looper per SensorEventQueue
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800150 // We map SensorEventListener to a SensorEventQueue, which holds the looper
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800151 synchronized (mSensorListeners) {
152 SensorEventQueue queue = mSensorListeners.get(listener);
153 if (queue == null) {
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700154 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
Aravind Akella11fce8e2015-07-09 14:11:45 -0700155 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
156 listener.getClass().getEnclosingClass().getName() :
157 listener.getClass().getName();
158 queue = new SensorEventQueue(listener, looper, this, fullClassName);
Aravind Akella88445992015-02-26 17:05:28 -0800159 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700160 queue.dispose();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800161 return false;
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700162 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800163 mSensorListeners.put(listener, queue);
164 return true;
165 } else {
Aravind Akella88445992015-02-26 17:05:28 -0800166 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
Jeff Brown25157e42012-04-16 12:13:05 -0700167 }
168 }
Jeff Brown25157e42012-04-16 12:13:05 -0700169 }
170
171 /** @hide */
172 @Override
173 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800174 // Trigger Sensors should use the cancelTriggerSensor call.
Aravind Akella27900352014-06-03 19:20:42 -0700175 if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800176 return;
177 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800178
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800179 synchronized (mSensorListeners) {
180 SensorEventQueue queue = mSensorListeners.get(listener);
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700181 if (queue != null) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800182 boolean result;
183 if (sensor == null) {
184 result = queue.removeAllSensors();
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700185 } else {
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700186 result = queue.removeSensor(sensor, true);
Jaikumar Ganesh1aab1db2013-03-13 15:00:21 -0700187 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800188 if (result && !queue.hasSensors()) {
189 mSensorListeners.remove(listener);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800190 queue.dispose();
Jeff Brown25157e42012-04-16 12:13:05 -0700191 }
192 }
193 }
194 }
195
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800196 /** @hide */
197 @Override
198 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
199 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
Jeff Brown25157e42012-04-16 12:13:05 -0700200
Aravind Akella11fce8e2015-07-09 14:11:45 -0700201 if (listener == null) throw new IllegalArgumentException("listener cannot be null");
202
Aravind Akella27900352014-06-03 19:20:42 -0700203 if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800204
205 synchronized (mTriggerListeners) {
206 TriggerEventQueue queue = mTriggerListeners.get(listener);
207 if (queue == null) {
Aravind Akella11fce8e2015-07-09 14:11:45 -0700208 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
209 listener.getClass().getEnclosingClass().getName() :
210 listener.getClass().getName();
211 queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName);
Aravind Akella88445992015-02-26 17:05:28 -0800212 if (!queue.addSensor(sensor, 0, 0)) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800213 queue.dispose();
214 return false;
215 }
216 mTriggerListeners.put(listener, queue);
217 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800218 } else {
Aravind Akella88445992015-02-26 17:05:28 -0800219 return queue.addSensor(sensor, 0, 0);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800220 }
221 }
222 }
Jeff Brown25157e42012-04-16 12:13:05 -0700223
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800224 /** @hide */
225 @Override
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700226 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
227 boolean disable) {
Aravind Akella27900352014-06-03 19:20:42 -0700228 if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800229 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 {
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700238 result = queue.removeSensor(sensor, disable);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800239 }
240 if (result && !queue.hasSensors()) {
241 mTriggerListeners.remove(listener);
242 queue.dispose();
243 }
244 return result;
245 }
246 return false;
247 }
248 }
249
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700250 protected boolean flushImpl(SensorEventListener listener) {
251 if (listener == null) throw new IllegalArgumentException("listener cannot be null");
Aravind Akellab4c76b12013-06-27 12:04:16 -0700252
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700253 synchronized (mSensorListeners) {
254 SensorEventQueue queue = mSensorListeners.get(listener);
255 if (queue == null) {
256 return false;
257 } else {
258 return (queue.flush() == 0);
259 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700260 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700261 }
262
Aravind Akellad123b512015-06-29 12:35:51 -0700263 protected boolean initDataInjectionImpl(boolean enable) {
Peng Xuaa957272016-03-15 18:16:45 -0700264 synchronized (sLock) {
Aravind Akellad123b512015-06-29 12:35:51 -0700265 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 }
Aravind Akellad123b512015-06-29 12:35:51 -0700272 // Initialize a client for data_injection.
Peng Xuaa957272016-03-15 18:16:45 -0700273 if (sInjectEventQueue == null) {
274 sInjectEventQueue = new InjectEventQueue(mMainLooper, this,
Aravind Akella11fce8e2015-07-09 14:11:45 -0700275 mContext.getPackageName());
Aravind Akellad123b512015-06-29 12:35:51 -0700276 }
277 } else {
278 // If data injection is being disabled clean up the native resources.
Peng Xuaa957272016-03-15 18:16:45 -0700279 if (sInjectEventQueue != null) {
280 sInjectEventQueue.dispose();
281 sInjectEventQueue = null;
Aravind Akellad123b512015-06-29 12:35:51 -0700282 }
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700283 }
284 return true;
285 }
286 }
287
288 protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
289 long timestamp) {
Peng Xuaa957272016-03-15 18:16:45 -0700290 synchronized (sLock) {
291 if (sInjectEventQueue == null) {
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700292 Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
293 return false;
294 }
Peng Xuaa957272016-03-15 18:16:45 -0700295 int ret = sInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700296 timestamp);
297 // If there are any errors in data injection clean up the native resources.
298 if (ret != 0) {
Peng Xuaa957272016-03-15 18:16:45 -0700299 sInjectEventQueue.dispose();
300 sInjectEventQueue = null;
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700301 }
302 return ret == 0;
303 }
304 }
305
Peng Xua35b5532016-01-20 00:05:45 -0800306 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
Peng Xufb1c9412016-03-29 21:50:43 -0700357 for (Map.Entry<DynamicSensorCallback, Handler> entry :
Peng Xua35b5532016-01-20 00:05:45 -0800358 mDynamicSensorCallbacks.entrySet()) {
Peng Xufb1c9412016-03-29 21:50:43 -0700359 final DynamicSensorCallback callback = entry.getKey();
Peng Xua35b5532016-01-20 00:05:45 -0800360 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(
Peng Xufb1c9412016-03-29 21:50:43 -0700416 DynamicSensorCallback callback, Handler handler) {
Peng Xua35b5532016-01-20 00:05:45 -0800417 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(
Peng Xufb1c9412016-03-29 21:50:43 -0700435 DynamicSensorCallback callback) {
Peng Xua35b5532016-01-20 00:05:45 -0800436 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
Mathias Agopiandb772d82013-01-31 19:31:12 -0800487 /*
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800488 * BaseEventQueue is the communication channel with the sensor service,
489 * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700490 * 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.
Mathias Agopiandb772d82013-01-31 19:31:12 -0800494 */
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800495 private static abstract class BaseEventQueue {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700496 private static native long nativeInitBaseEventQueue(long nativeManager,
Peng Xua2958352016-01-26 18:42:17 -0800497 WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
Svet Ganovb9d71a62015-04-30 10:38:13 -0700498 String packageName, int mode, String opPackageName);
Ashok Bhat4838e332014-01-03 14:37:19 +0000499 private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
Aravind Akella88445992015-02-26 17:05:28 -0800500 int maxBatchReportLatencyUs);
Ashok Bhat4838e332014-01-03 14:37:19 +0000501 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);
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700504 private static native int nativeInjectSensorData(long eventQ, int handle,
Svet Ganovb9d71a62015-04-30 10:38:13 -0700505 float[] values,int accuracy, long timestamp);
506
Ashok Bhat4838e332014-01-03 14:37:19 +0000507 private long nSensorEventQueue;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800508 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800509 protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
Mathias Agopiandb772d82013-01-31 19:31:12 -0800510 private final CloseGuard mCloseGuard = CloseGuard.get();
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700511 protected final SystemSensorManager mManager;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800512
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700513 protected static final int OPERATING_MODE_NORMAL = 0;
514 protected static final int OPERATING_MODE_DATA_INJECTION = 1;
515
Aravind Akella11fce8e2015-07-09 14:11:45 -0700516 BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
517 if (packageName == null) packageName = "";
Svet Ganovb9d71a62015-04-30 10:38:13 -0700518 nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
Peng Xua2958352016-01-26 18:42:17 -0800519 new WeakReference<>(this), looper.getQueue(),
Aravind Akella11fce8e2015-07-09 14:11:45 -0700520 packageName, mode, manager.mContext.getOpPackageName());
Mathias Agopiandb772d82013-01-31 19:31:12 -0800521 mCloseGuard.open("dispose");
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700522 mManager = manager;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800523 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800524
Mathias Agopiandb772d82013-01-31 19:31:12 -0800525 public void dispose() {
526 dispose(false);
527 }
528
Aravind Akellab4c76b12013-06-27 12:04:16 -0700529 public boolean addSensor(
Aravind Akella88445992015-02-26 17:05:28 -0800530 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800531 // Check if already present.
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700532 int handle = sensor.getHandle();
533 if (mActiveSensors.get(handle)) return false;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800534
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700535 // Get ready to receive events before calling enable.
536 mActiveSensors.put(handle, true);
537 addSensorEvent(sensor);
Aravind Akella88445992015-02-26 17:05:28 -0800538 if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
Aravind Akellab4c76b12013-06-27 12:04:16 -0700539 // Try continuous mode if batching fails.
540 if (maxBatchReportLatencyUs == 0 ||
Aravind Akella88445992015-02-26 17:05:28 -0800541 maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
Aravind Akellab4c76b12013-06-27 12:04:16 -0700542 removeSensor(sensor, false);
543 return false;
544 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800545 }
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700546 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800547 }
548
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800549 public boolean removeAllSensors() {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800550 for (int i=0 ; i<mActiveSensors.size(); i++) {
551 if (mActiveSensors.valueAt(i) == true) {
552 int handle = mActiveSensors.keyAt(i);
Svet Ganovb9d71a62015-04-30 10:38:13 -0700553 Sensor sensor = mManager.mHandleToSensor.get(handle);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800554 if (sensor != null) {
555 disableSensor(sensor);
556 mActiveSensors.put(handle, false);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700557 removeSensorEvent(sensor);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800558 } else {
Peng Xua35b5532016-01-20 00:05:45 -0800559 // sensor just disconnected -- just ignore.
Mathias Agopiandb772d82013-01-31 19:31:12 -0800560 }
561 }
562 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800563 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800564 }
565
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700566 public boolean removeSensor(Sensor sensor, boolean disable) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800567 final int handle = sensor.getHandle();
568 if (mActiveSensors.get(handle)) {
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700569 if (disable) disableSensor(sensor);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800570 mActiveSensors.put(sensor.getHandle(), false);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700571 removeSensorEvent(sensor);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800572 return true;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800573 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800574 return false;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800575 }
576
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700577 public int flush() {
Aravind Akellab4c76b12013-06-27 12:04:16 -0700578 if (nSensorEventQueue == 0) throw new NullPointerException();
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700579 return nativeFlushSensor(nSensorEventQueue);
Aravind Akellab4c76b12013-06-27 12:04:16 -0700580 }
581
Mathias Agopiandb772d82013-01-31 19:31:12 -0800582 public boolean hasSensors() {
583 // no more sensors are set
584 return mActiveSensors.indexOfValue(true) >= 0;
585 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800586
Mathias Agopiandb772d82013-01-31 19:31:12 -0800587 @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
Aravind Akellab4c76b12013-06-27 12:04:16 -0700609 private int enableSensor(
Aravind Akella88445992015-02-26 17:05:28 -0800610 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800611 if (nSensorEventQueue == 0) throw new NullPointerException();
612 if (sensor == null) throw new NullPointerException();
Aravind Akellab4c76b12013-06-27 12:04:16 -0700613 return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
Aravind Akella88445992015-02-26 17:05:28 -0800614 maxBatchReportLatencyUs);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800615 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700616
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700617 protected int injectSensorDataBase(int handle, float[] values, int accuracy,
618 long timestamp) {
619 return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
620 }
621
Mathias Agopiandb772d82013-01-31 19:31:12 -0800622 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 }
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800627 protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
628 long timestamp);
Aravind Akellab4c76b12013-06-27 12:04:16 -0700629 protected abstract void dispatchFlushCompleteEvent(int handle);
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700630
Peng Xua2958352016-01-26 18:42:17 -0800631 protected void dispatchAdditionalInfoEvent(
632 int handle, int type, int serial, float[] floatValues, int[] intValues) {
633 // default implementation is do nothing
634 }
635
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700636 protected abstract void addSensorEvent(Sensor sensor);
637 protected abstract void removeSensorEvent(Sensor sensor);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800638 }
639
640 static final class SensorEventQueue extends BaseEventQueue {
641 private final SensorEventListener mListener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700642 private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800643
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700644 public SensorEventQueue(SensorEventListener listener, Looper looper,
Aravind Akella11fce8e2015-07-09 14:11:45 -0700645 SystemSensorManager manager, String packageName) {
646 super(looper, manager, OPERATING_MODE_NORMAL, packageName);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800647 mListener = listener;
648 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800649
Aravind Akella31d14ce2013-10-22 20:04:22 -0700650 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700651 public void addSensorEvent(Sensor sensor) {
652 SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
653 mManager.mTargetSdkLevel));
Aravind Akella31d14ce2013-10-22 20:04:22 -0700654 synchronized (mSensorsEvents) {
655 mSensorsEvents.put(sensor.getHandle(), t);
656 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700657 }
658
Aravind Akella31d14ce2013-10-22 20:04:22 -0700659 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700660 public void removeSensorEvent(Sensor sensor) {
Aravind Akella31d14ce2013-10-22 20:04:22 -0700661 synchronized (mSensorsEvents) {
662 mSensorsEvents.delete(sensor.getHandle());
663 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700664 }
665
Mathias Agopiandb772d82013-01-31 19:31:12 -0800666 // Called from native code.
667 @SuppressWarnings("unused")
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800668 @Override
669 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
670 long timestamp) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700671 final Sensor sensor = mManager.mHandleToSensor.get(handle);
Peng Xua35b5532016-01-20 00:05:45 -0800672 if (sensor == null) {
673 // sensor disconnected
674 return;
675 }
676
Aravind Akella31d14ce2013-10-22 20:04:22 -0700677 SensorEvent t = null;
678 synchronized (mSensorsEvents) {
679 t = mSensorsEvents.get(handle);
680 }
681
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700682 if (t == null) {
Aravind Akella31d14ce2013-10-22 20:04:22 -0700683 // This may happen if the client has unregistered and there are pending events in
684 // the queue waiting to be delivered. Ignore.
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700685 return;
686 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700687 // 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;
Etienne Le Grandaf805102014-05-16 12:21:41 -0700692
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);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800698 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700699 mListener.onSensorChanged(t);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800700 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700701
Peng Xua2958352016-01-26 18:42:17 -0800702 // Called from native code.
Aravind Akellab4c76b12013-06-27 12:04:16 -0700703 @SuppressWarnings("unused")
Peng Xua2958352016-01-26 18:42:17 -0800704 @Override
Aravind Akellab4c76b12013-06-27 12:04:16 -0700705 protected void dispatchFlushCompleteEvent(int handle) {
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700706 if (mListener instanceof SensorEventListener2) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700707 final Sensor sensor = mManager.mHandleToSensor.get(handle);
Peng Xua35b5532016-01-20 00:05:45 -0800708 if (sensor == null) {
709 // sensor disconnected
710 return;
711 }
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700712 ((SensorEventListener2)mListener).onFlushCompleted(sensor);
Aravind Akellab4c76b12013-06-27 12:04:16 -0700713 }
714 return;
715 }
Peng Xua2958352016-01-26 18:42:17 -0800716
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 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800733 }
734
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800735 static final class TriggerEventQueue extends BaseEventQueue {
736 private final TriggerEventListener mListener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700737 private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
Mathias Agopiandb772d82013-01-31 19:31:12 -0800738
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800739 public TriggerEventQueue(TriggerEventListener listener, Looper looper,
Aravind Akella11fce8e2015-07-09 14:11:45 -0700740 SystemSensorManager manager, String packageName) {
741 super(looper, manager, OPERATING_MODE_NORMAL, packageName);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800742 mListener = listener;
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700743 }
744
Aravind Akella31d14ce2013-10-22 20:04:22 -0700745 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700746 public void addSensorEvent(Sensor sensor) {
747 TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
748 mManager.mTargetSdkLevel));
Aravind Akella31d14ce2013-10-22 20:04:22 -0700749 synchronized (mTriggerEvents) {
750 mTriggerEvents.put(sensor.getHandle(), t);
751 }
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700752 }
753
Aravind Akella31d14ce2013-10-22 20:04:22 -0700754 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700755 public void removeSensorEvent(Sensor sensor) {
Aravind Akella31d14ce2013-10-22 20:04:22 -0700756 synchronized (mTriggerEvents) {
757 mTriggerEvents.delete(sensor.getHandle());
758 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800759 }
760
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800761 // Called from native code.
762 @SuppressWarnings("unused")
763 @Override
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700764 protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
765 long timestamp) {
Svet Ganovb9d71a62015-04-30 10:38:13 -0700766 final Sensor sensor = mManager.mHandleToSensor.get(handle);
Peng Xua35b5532016-01-20 00:05:45 -0800767 if (sensor == null) {
768 // sensor disconnected
769 return;
770 }
Aravind Akella31d14ce2013-10-22 20:04:22 -0700771 TriggerEvent t = null;
772 synchronized (mTriggerEvents) {
773 t = mTriggerEvents.get(handle);
774 }
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700775 if (t == null) {
776 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
777 return;
778 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800779
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700780 // Copy from the values array.
781 System.arraycopy(values, 0, t.values, 0, t.values.length);
782 t.timestamp = timestamp;
783 t.sensor = sensor;
Mathias Agopiandb772d82013-01-31 19:31:12 -0800784
Jaikumar Ganesh2e900892013-04-11 10:40:33 -0700785 // A trigger sensor is auto disabled. So just clean up and don't call native
786 // disable.
787 mManager.cancelTriggerSensorImpl(mListener, sensor, false);
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800788
Jaikumar Ganesh6d0c1d782013-03-27 17:41:33 -0700789 mListener.onTrigger(t);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800790 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700791
792 @SuppressWarnings("unused")
793 protected void dispatchFlushCompleteEvent(int handle) {
794 }
795 }
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700796
Svet Ganovb9d71a62015-04-30 10:38:13 -0700797 final class InjectEventQueue extends BaseEventQueue {
Aravind Akella11fce8e2015-07-09 14:11:45 -0700798 public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) {
799 super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName);
Aravind Akella18ebf732b2015-04-20 17:39:51 -0700800 }
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 }
Jeff Brown25157e42012-04-16 12:13:05 -0700826}