Loading core/java/android/hardware/FlushCompleteListener.java 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware; /** * Used for receiving a notification when a flush() has been successfully completed. * @hide */ public interface FlushCompleteListener { /** * Called after flush() is completed. This flush() could have been initiated by this application * or some other application. All the events in the batch at the point when the flush was called * have been delivered to the applications registered for those sensor events. * <p> * * @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called. * * @see android.hardware.SensorManager#flush(Sensor) */ public void onFlushCompleted(Sensor sensor); } core/java/android/hardware/Sensor.java +22 −0 Original line number Diff line number Diff line Loading @@ -319,6 +319,8 @@ public final class Sensor { private float mResolution; private float mPower; private int mMinDelay; private int mFifoReservedEventCount; private int mFifoMaxEventCount; Sensor() { } Loading Loading @@ -381,6 +383,26 @@ public final class Sensor { return mMinDelay; } /** * @return Number of events reserved for this sensor in the batch mode FIFO. This gives a * guarantee on the minimum number of events that can be batched * @hide */ public int getFifoReservedEventCount() { return mFifoReservedEventCount; } /** * @return Maximum number of events of this sensor that could be batched. If this value is zero * it indicates that batch mode is not supported for this sensor. If other applications * registered to batched sensors, the actual number of events that can be batched might be * smaller because the hardware FiFo will be partially used to batch the other sensors. * @hide */ public int getFifoMaxEventCount() { return mFifoMaxEventCount; } /** @hide */ public int getHandle() { return mHandle; Loading core/java/android/hardware/SensorManager.java +139 −26 Original line number Diff line number Diff line Loading @@ -608,8 +608,74 @@ public abstract class SensorManager { } /** * Registers a {@link android.hardware.SensorEventListener * SensorEventListener} for the given sensor. * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. If the * underlying hardware does not support batch mode, this defaults to * {@link #registerListener(SensorEventListener, Sensor, int)} and other parameters are are * ignored. In non-batch mode, all sensor events must be reported as soon as they are detected. * While in batch mode, sensor events do not need to be reported as soon as they are detected. * They can be temporarily stored in batches and reported in batches, as long as no event is * delayed by more than "maxBatchReportLatency" microseconds. That is, all events since the * previous batch are recorded and returned all at once. This allows to reduce the amount of * interrupts sent to the SoC, and allows the SoC to switch to a lower power state (Idle) while * the sensor is capturing and batching data. * <p> * Registering to a sensor in batch mode will not prevent the SoC from going to suspend mode. In * this case, the sensor will continue to gather events and store it in a hardware FIFO. If the * FIFO gets full before the AP wakes up again, some events will be lost, as the older events * get overwritten by new events in the hardware FIFO. This can be avoided by holding a wake * lock. If the application holds a wake lock, the SoC will not go to suspend mode, so no events * will be lost, as the events will be reported before the FIFO gets full. * </p> * <p> * Batching is always best effort. If a different application requests updates in continuous * mode, this application will also get events in continuous mode. Batch mode updates can be * unregistered by calling {@link #unregisterListener(SensorEventListener)}. * </p> * <p class="note"> * </p> * Note: Don't use this method with a one shot trigger sensor such as * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p> * * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object * that will receive the sensor events. * @param sensor The {@link android.hardware.Sensor Sensor} to register to. * @param rate The desired delay between two consecutive events in microseconds. This is only a * hint to the system. Events may be received faster or slower than the specified * rate. Usually events are received faster. Can be one of * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, * {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in * microseconds. * @param maxBatchReportLatency An event in the batch can be delayed by at most * maxBatchReportLatency microseconds. More events can be batched if this value is * large. If this is set to zero, batch mode is disabled and events are delivered in * continuous mode as soon as they are available which is equivalent to calling * {@link #registerListener(SensorEventListener, Sensor, int)}. * @param reservedFlags Always set to Zero. * @param flushCompleteListener A {@link android.hardware.FlushCompleteListener * FlushCompleteListener} object which is called when any application calls flush() * on this sensor and all the events in the batch at the time of calling flush() are * successfully delivered to the listeners. * @return true if batch mode is successfully enabled for this sensor, false otherwise. * @see #registerListener(SensorEventListener, Sensor, int) * @see #unregisterListener(SensorEventListener) * @see #flush(Sensor) * @throws IllegalArgumentException when sensor or listener is null or a trigger sensor. * @hide */ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags, FlushCompleteListener flushCompleteListener) { int delay = getDelay(rateUs); return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs, reservedFlags, flushCompleteListener); } /** * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given * sensor. Events are delivered in continuous mode as soon as they are available. To reduce the * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int, int, * FlushCompleteListener)} * * <p class="note"></p> * Note: Don't use this method with a one shot trigger sensor such as Loading Loading @@ -646,6 +712,7 @@ public abstract class SensorManager { * @see #registerListener(SensorEventListener, Sensor, int) * @see #unregisterListener(SensorEventListener) * @see #unregisterListener(SensorEventListener, Sensor) * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener) * * @throws IllegalArgumentException when sensor is null or a trigger sensor */ Loading @@ -655,31 +722,55 @@ public abstract class SensorManager { return false; } int delay = -1; switch (rate) { case SENSOR_DELAY_FASTEST: delay = 0; break; case SENSOR_DELAY_GAME: delay = 20000; break; case SENSOR_DELAY_UI: delay = 66667; break; case SENSOR_DELAY_NORMAL: delay = 200000; break; default: delay = rate; break; int delay = getDelay(rate); return registerListenerImpl(listener, sensor, delay, handler, 0, 0, null); } return registerListenerImpl(listener, sensor, delay, handler); /** * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. * @param handler * The {@link android.os.Handler Handler} the * {@link android.hardware.SensorEvent sensor events} will be * delivered to. * * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener) * @hide */ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags, Handler handler, FlushCompleteListener flushCompleteListener) { int delayUs = getDelay(rateUs); return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs, reservedFlags, flushCompleteListener); } /** @hide */ protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, int delay, Handler handler); int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags, FlushCompleteListener flushCompleteListener); /** * Flushes the batch FIFO of the given sensor. If there are events in the FIFO of this sensor, * they are returned as if the batch timeout has expired. Events are returned in the * usual way through the SensorEventListener. This call doesn't effect the batch timeout for * this sensor. This call is asynchronous and returns immediately. FlushCompleteListener is * called after all the events in the batch at the time of calling this method have been * delivered successfully. * @param sensor * The {@link android.hardware.Sensor Sensor} to flush. * @return true if the flush is initiated successfully. false if the sensor isn't active * i.e no application is registered for updates from this sensor. * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener) * @throws IllegalArgumentException when sensor is null or a trigger sensor. * @hide */ public boolean flush(Sensor sensor) { return flushImpl(sensor); } /** @hide */ protected abstract boolean flushImpl(Sensor sensor); /** * <p> Loading Loading @@ -1407,4 +1498,26 @@ public abstract class SensorManager { return mLegacySensorManager; } } private static int getDelay(int rate) { int delay = -1; switch (rate) { case SENSOR_DELAY_FASTEST: delay = 0; break; case SENSOR_DELAY_GAME: delay = 20000; break; case SENSOR_DELAY_UI: delay = 66667; break; case SENSOR_DELAY_NORMAL: delay = 200000; break; default: delay = rate; break; } return delay; } } core/java/android/hardware/SystemSensorManager.java +95 −21 Original line number Diff line number Diff line Loading @@ -93,30 +93,35 @@ public class SystemSensorManager extends SensorManager { /** @hide */ @Override protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, int delay, Handler handler) { int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags, FlushCompleteListener flushCompleteListener) { if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); if (listener == null) throw new IllegalArgumentException("listener cannot be null"); if (reservedFlags != 0) throw new IllegalArgumentException("reservedFlags should be zero"); if (delayUs < 0) throw new IllegalArgumentException("rateUs should be positive"); if (maxBatchReportLatencyUs < 0) throw new IllegalArgumentException("maxBatchReportLatencyUs should be positive"); // Trigger Sensors should use the requestTriggerSensor call. if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) throw new IllegalArgumentException("Trigger Sensors cannot use registerListener"); // Invariants to preserve: // - one Looper per SensorEventListener // - one Looper per SensorEventQueue // We map SensorEventListener to a SensorEventQueue, which holds the looper if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); // Trigger Sensors should use the requestTriggerSensor call. if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) return false; synchronized (mSensorListeners) { SensorEventQueue queue = mSensorListeners.get(listener); if (queue == null) { Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; queue = new SensorEventQueue(listener, looper, this); if (!queue.addSensor(sensor, delay)) { queue = new SensorEventQueue(listener, looper, this, flushCompleteListener); if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) { queue.dispose(); return false; } mSensorListeners.put(listener, queue); return true; } else { return queue.addSensor(sensor, delay); return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags); } } } Loading Loading @@ -157,14 +162,14 @@ public class SystemSensorManager extends SensorManager { TriggerEventQueue queue = mTriggerListeners.get(listener); if (queue == null) { queue = new TriggerEventQueue(listener, mMainLooper, this); if (!queue.addSensor(sensor, 0)) { if (!queue.addSensor(sensor, 0, 0, 0)) { queue.dispose(); return false; } mTriggerListeners.put(listener, queue); return true; } else { return queue.addSensor(sensor, 0); return queue.addSensor(sensor, 0, 0, 0); } } } Loading Loading @@ -195,6 +200,18 @@ public class SystemSensorManager extends SensorManager { } } protected boolean flushImpl(Sensor sensor) { if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); if(Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) throw new IllegalArgumentException("Trigger Sensors cannot call flush"); FlushEventQueue queue = new FlushEventQueue(mMainLooper, this); if (queue.flushSensor(sensor) != 0) { return false; } return true; } /* * BaseEventQueue is the communication channel with the sensor service, * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between Loading @@ -202,11 +219,12 @@ public class SystemSensorManager extends SensorManager { */ private static abstract class BaseEventQueue { private native int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ, float[] scratch); private static native int nativeEnableSensor(int eventQ, int handle, int us); private static native int nativeEnableSensor(int eventQ, int handle, int rateUs, int maxBatchReportLatencyUs, int reservedFlags); private static native int nativeDisableSensor(int eventQ, int handle); private static native void nativeDestroySensorEventQueue(int eventQ); private static native int nativeFlushSensor(int eventQ, int handle); private int nSensorEventQueue; private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); Loading @@ -225,7 +243,8 @@ public class SystemSensorManager extends SensorManager { dispose(false); } public boolean addSensor(Sensor sensor, int delay) { public boolean addSensor( Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) { // Check if already present. int handle = sensor.getHandle(); if (mActiveSensors.get(handle)) return false; Loading @@ -233,10 +252,14 @@ public class SystemSensorManager extends SensorManager { // Get ready to receive events before calling enable. mActiveSensors.put(handle, true); addSensorEvent(sensor); if (enableSensor(sensor, delay) != 0) { if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) { // Try continuous mode if batching fails. if (maxBatchReportLatencyUs == 0 || maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) { removeSensor(sensor, false); return false; } } return true; } Loading Loading @@ -268,6 +291,12 @@ public class SystemSensorManager extends SensorManager { return false; } public int flushSensor(Sensor sensor) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); return nativeFlushSensor(nSensorEventQueue, sensor.getHandle()); } public boolean hasSensors() { // no more sensors are set return mActiveSensors.indexOfValue(true) >= 0; Loading Loading @@ -295,11 +324,14 @@ public class SystemSensorManager extends SensorManager { } } private int enableSensor(Sensor sensor, int us) { private int enableSensor( Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us); return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs, maxBatchReportLatencyUs, reservedFlags); } private int disableSensor(Sensor sensor) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); Loading @@ -307,6 +339,7 @@ public class SystemSensorManager extends SensorManager { } protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp); protected abstract void dispatchFlushCompleteEvent(int handle); protected abstract void addSensorEvent(Sensor sensor); protected abstract void removeSensorEvent(Sensor sensor); Loading @@ -314,12 +347,14 @@ public class SystemSensorManager extends SensorManager { static final class SensorEventQueue extends BaseEventQueue { private final SensorEventListener mListener; private final FlushCompleteListener mFlushCompleteListener; private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>(); public SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager) { SystemSensorManager manager, FlushCompleteListener flushCompleteListener) { super(looper, manager); mListener = listener; mFlushCompleteListener = flushCompleteListener; } public void addSensorEvent(Sensor sensor) { Loading Loading @@ -370,6 +405,15 @@ public class SystemSensorManager extends SensorManager { } mListener.onSensorChanged(t); } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { final Sensor sensor = sHandleToSensor.get(handle); if (mFlushCompleteListener != null) { mFlushCompleteListener.onFlushCompleted(sensor); } return; } } static final class TriggerEventQueue extends BaseEventQueue { Loading Loading @@ -415,5 +459,35 @@ public class SystemSensorManager extends SensorManager { mListener.onTrigger(t); } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { } } static final class FlushEventQueue extends BaseEventQueue { public FlushEventQueue(Looper looper, SystemSensorManager manager) { super(looper, manager); } @SuppressWarnings("unused") @Override protected void dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp) { } @Override @SuppressWarnings("unused") protected void addSensorEvent(Sensor sensor) { } @Override @SuppressWarnings("unused") protected void removeSensorEvent(Sensor sensor) { } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { } } } core/jni/android_hardware_SensorManager.cpp +41 −11 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ static struct { jclass clazz; jmethodID dispatchSensorEvent; jmethodID dispatchFlushCompleteEvent; } gBaseEventQueueClassInfo; namespace android { Loading @@ -46,6 +47,8 @@ struct SensorOffsets jfieldID resolution; jfieldID power; jfieldID minDelay; jfieldID fifoReservedEventCount; jfieldID fifoMaxEventCount; } gSensorOffsets; Loading @@ -67,6 +70,9 @@ nativeClassInit (JNIEnv *_env, jclass _this) sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F"); sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F"); sensorOffsets.minDelay = _env->GetFieldID(sensorClass, "mMinDelay", "I"); sensorOffsets.fifoReservedEventCount = _env->GetFieldID(sensorClass, "mFifoReservedEventCount", "I"); sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount", "I"); } static jint Loading @@ -92,7 +98,9 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next) env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution()); env->SetFloatField(sensor, sensorOffsets.power, list->getPowerUsage()); env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay()); env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount, list->getFifoReservedEventCount()); env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount()); next++; return size_t(next) < count ? next : 0; } Loading Loading @@ -150,12 +158,20 @@ private: env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data); } if (buffer[i].type == SENSOR_TYPE_META_DATA) { // This is a flush complete sensor event. Call dispatchFlushCompleteEvent // method. env->CallVoidMethod(mReceiverObject, gBaseEventQueueClassInfo.dispatchFlushCompleteEvent, buffer[i].meta_data.sensor); } else { env->CallVoidMethod(mReceiverObject, gBaseEventQueueClassInfo.dispatchSensorEvent, buffer[i].sensor, mScratch, buffer[i].vector.status, buffer[i].timestamp); } if (env->ExceptionCheck()) { ALOGE("Exception dispatching input event."); Loading Loading @@ -186,9 +202,11 @@ static jint nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ return jint(receiver.get()); } static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint us) { static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint rate_us, jint maxBatchReportLatency, jint reservedFlags) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); return receiver->getSensorEventQueue()->enableSensor(handle, us); return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency, reservedFlags); } static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) { Loading @@ -202,6 +220,10 @@ static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jint eventQ receiver->decStrong((void*)nativeInitSensorEventQueue); } static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); return receiver->getSensorEventQueue()->flushSensor(handle); } //---------------------------------------------------------------------------- Loading @@ -221,7 +243,7 @@ static JNINativeMethod gBaseEventQueueMethods[] = { (void*)nativeInitSensorEventQueue }, {"nativeEnableSensor", "(III)I", "(IIIII)I", (void*)nativeEnableSensor }, {"nativeDisableSensor", Loading @@ -231,6 +253,10 @@ static JNINativeMethod gBaseEventQueueMethods[] = { {"nativeDestroySensorEventQueue", "(I)V", (void*)nativeDestroySensorEventQueue }, {"nativeFlushSensor", "(II)I", (void*)nativeFlushSensor }, }; }; // namespace android Loading Loading @@ -260,5 +286,9 @@ int register_android_hardware_SensorManager(JNIEnv *env) gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V"); GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchFlushCompleteEvent, gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V"); return 0; } Loading
core/java/android/hardware/FlushCompleteListener.java 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware; /** * Used for receiving a notification when a flush() has been successfully completed. * @hide */ public interface FlushCompleteListener { /** * Called after flush() is completed. This flush() could have been initiated by this application * or some other application. All the events in the batch at the point when the flush was called * have been delivered to the applications registered for those sensor events. * <p> * * @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called. * * @see android.hardware.SensorManager#flush(Sensor) */ public void onFlushCompleted(Sensor sensor); }
core/java/android/hardware/Sensor.java +22 −0 Original line number Diff line number Diff line Loading @@ -319,6 +319,8 @@ public final class Sensor { private float mResolution; private float mPower; private int mMinDelay; private int mFifoReservedEventCount; private int mFifoMaxEventCount; Sensor() { } Loading Loading @@ -381,6 +383,26 @@ public final class Sensor { return mMinDelay; } /** * @return Number of events reserved for this sensor in the batch mode FIFO. This gives a * guarantee on the minimum number of events that can be batched * @hide */ public int getFifoReservedEventCount() { return mFifoReservedEventCount; } /** * @return Maximum number of events of this sensor that could be batched. If this value is zero * it indicates that batch mode is not supported for this sensor. If other applications * registered to batched sensors, the actual number of events that can be batched might be * smaller because the hardware FiFo will be partially used to batch the other sensors. * @hide */ public int getFifoMaxEventCount() { return mFifoMaxEventCount; } /** @hide */ public int getHandle() { return mHandle; Loading
core/java/android/hardware/SensorManager.java +139 −26 Original line number Diff line number Diff line Loading @@ -608,8 +608,74 @@ public abstract class SensorManager { } /** * Registers a {@link android.hardware.SensorEventListener * SensorEventListener} for the given sensor. * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. If the * underlying hardware does not support batch mode, this defaults to * {@link #registerListener(SensorEventListener, Sensor, int)} and other parameters are are * ignored. In non-batch mode, all sensor events must be reported as soon as they are detected. * While in batch mode, sensor events do not need to be reported as soon as they are detected. * They can be temporarily stored in batches and reported in batches, as long as no event is * delayed by more than "maxBatchReportLatency" microseconds. That is, all events since the * previous batch are recorded and returned all at once. This allows to reduce the amount of * interrupts sent to the SoC, and allows the SoC to switch to a lower power state (Idle) while * the sensor is capturing and batching data. * <p> * Registering to a sensor in batch mode will not prevent the SoC from going to suspend mode. In * this case, the sensor will continue to gather events and store it in a hardware FIFO. If the * FIFO gets full before the AP wakes up again, some events will be lost, as the older events * get overwritten by new events in the hardware FIFO. This can be avoided by holding a wake * lock. If the application holds a wake lock, the SoC will not go to suspend mode, so no events * will be lost, as the events will be reported before the FIFO gets full. * </p> * <p> * Batching is always best effort. If a different application requests updates in continuous * mode, this application will also get events in continuous mode. Batch mode updates can be * unregistered by calling {@link #unregisterListener(SensorEventListener)}. * </p> * <p class="note"> * </p> * Note: Don't use this method with a one shot trigger sensor such as * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p> * * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object * that will receive the sensor events. * @param sensor The {@link android.hardware.Sensor Sensor} to register to. * @param rate The desired delay between two consecutive events in microseconds. This is only a * hint to the system. Events may be received faster or slower than the specified * rate. Usually events are received faster. Can be one of * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, * {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in * microseconds. * @param maxBatchReportLatency An event in the batch can be delayed by at most * maxBatchReportLatency microseconds. More events can be batched if this value is * large. If this is set to zero, batch mode is disabled and events are delivered in * continuous mode as soon as they are available which is equivalent to calling * {@link #registerListener(SensorEventListener, Sensor, int)}. * @param reservedFlags Always set to Zero. * @param flushCompleteListener A {@link android.hardware.FlushCompleteListener * FlushCompleteListener} object which is called when any application calls flush() * on this sensor and all the events in the batch at the time of calling flush() are * successfully delivered to the listeners. * @return true if batch mode is successfully enabled for this sensor, false otherwise. * @see #registerListener(SensorEventListener, Sensor, int) * @see #unregisterListener(SensorEventListener) * @see #flush(Sensor) * @throws IllegalArgumentException when sensor or listener is null or a trigger sensor. * @hide */ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags, FlushCompleteListener flushCompleteListener) { int delay = getDelay(rateUs); return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs, reservedFlags, flushCompleteListener); } /** * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given * sensor. Events are delivered in continuous mode as soon as they are available. To reduce the * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int, int, * FlushCompleteListener)} * * <p class="note"></p> * Note: Don't use this method with a one shot trigger sensor such as Loading Loading @@ -646,6 +712,7 @@ public abstract class SensorManager { * @see #registerListener(SensorEventListener, Sensor, int) * @see #unregisterListener(SensorEventListener) * @see #unregisterListener(SensorEventListener, Sensor) * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener) * * @throws IllegalArgumentException when sensor is null or a trigger sensor */ Loading @@ -655,31 +722,55 @@ public abstract class SensorManager { return false; } int delay = -1; switch (rate) { case SENSOR_DELAY_FASTEST: delay = 0; break; case SENSOR_DELAY_GAME: delay = 20000; break; case SENSOR_DELAY_UI: delay = 66667; break; case SENSOR_DELAY_NORMAL: delay = 200000; break; default: delay = rate; break; int delay = getDelay(rate); return registerListenerImpl(listener, sensor, delay, handler, 0, 0, null); } return registerListenerImpl(listener, sensor, delay, handler); /** * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. * @param handler * The {@link android.os.Handler Handler} the * {@link android.hardware.SensorEvent sensor events} will be * delivered to. * * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener) * @hide */ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags, Handler handler, FlushCompleteListener flushCompleteListener) { int delayUs = getDelay(rateUs); return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs, reservedFlags, flushCompleteListener); } /** @hide */ protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, int delay, Handler handler); int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags, FlushCompleteListener flushCompleteListener); /** * Flushes the batch FIFO of the given sensor. If there are events in the FIFO of this sensor, * they are returned as if the batch timeout has expired. Events are returned in the * usual way through the SensorEventListener. This call doesn't effect the batch timeout for * this sensor. This call is asynchronous and returns immediately. FlushCompleteListener is * called after all the events in the batch at the time of calling this method have been * delivered successfully. * @param sensor * The {@link android.hardware.Sensor Sensor} to flush. * @return true if the flush is initiated successfully. false if the sensor isn't active * i.e no application is registered for updates from this sensor. * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener) * @throws IllegalArgumentException when sensor is null or a trigger sensor. * @hide */ public boolean flush(Sensor sensor) { return flushImpl(sensor); } /** @hide */ protected abstract boolean flushImpl(Sensor sensor); /** * <p> Loading Loading @@ -1407,4 +1498,26 @@ public abstract class SensorManager { return mLegacySensorManager; } } private static int getDelay(int rate) { int delay = -1; switch (rate) { case SENSOR_DELAY_FASTEST: delay = 0; break; case SENSOR_DELAY_GAME: delay = 20000; break; case SENSOR_DELAY_UI: delay = 66667; break; case SENSOR_DELAY_NORMAL: delay = 200000; break; default: delay = rate; break; } return delay; } }
core/java/android/hardware/SystemSensorManager.java +95 −21 Original line number Diff line number Diff line Loading @@ -93,30 +93,35 @@ public class SystemSensorManager extends SensorManager { /** @hide */ @Override protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, int delay, Handler handler) { int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags, FlushCompleteListener flushCompleteListener) { if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); if (listener == null) throw new IllegalArgumentException("listener cannot be null"); if (reservedFlags != 0) throw new IllegalArgumentException("reservedFlags should be zero"); if (delayUs < 0) throw new IllegalArgumentException("rateUs should be positive"); if (maxBatchReportLatencyUs < 0) throw new IllegalArgumentException("maxBatchReportLatencyUs should be positive"); // Trigger Sensors should use the requestTriggerSensor call. if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) throw new IllegalArgumentException("Trigger Sensors cannot use registerListener"); // Invariants to preserve: // - one Looper per SensorEventListener // - one Looper per SensorEventQueue // We map SensorEventListener to a SensorEventQueue, which holds the looper if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); // Trigger Sensors should use the requestTriggerSensor call. if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) return false; synchronized (mSensorListeners) { SensorEventQueue queue = mSensorListeners.get(listener); if (queue == null) { Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; queue = new SensorEventQueue(listener, looper, this); if (!queue.addSensor(sensor, delay)) { queue = new SensorEventQueue(listener, looper, this, flushCompleteListener); if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) { queue.dispose(); return false; } mSensorListeners.put(listener, queue); return true; } else { return queue.addSensor(sensor, delay); return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags); } } } Loading Loading @@ -157,14 +162,14 @@ public class SystemSensorManager extends SensorManager { TriggerEventQueue queue = mTriggerListeners.get(listener); if (queue == null) { queue = new TriggerEventQueue(listener, mMainLooper, this); if (!queue.addSensor(sensor, 0)) { if (!queue.addSensor(sensor, 0, 0, 0)) { queue.dispose(); return false; } mTriggerListeners.put(listener, queue); return true; } else { return queue.addSensor(sensor, 0); return queue.addSensor(sensor, 0, 0, 0); } } } Loading Loading @@ -195,6 +200,18 @@ public class SystemSensorManager extends SensorManager { } } protected boolean flushImpl(Sensor sensor) { if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); if(Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) throw new IllegalArgumentException("Trigger Sensors cannot call flush"); FlushEventQueue queue = new FlushEventQueue(mMainLooper, this); if (queue.flushSensor(sensor) != 0) { return false; } return true; } /* * BaseEventQueue is the communication channel with the sensor service, * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between Loading @@ -202,11 +219,12 @@ public class SystemSensorManager extends SensorManager { */ private static abstract class BaseEventQueue { private native int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ, float[] scratch); private static native int nativeEnableSensor(int eventQ, int handle, int us); private static native int nativeEnableSensor(int eventQ, int handle, int rateUs, int maxBatchReportLatencyUs, int reservedFlags); private static native int nativeDisableSensor(int eventQ, int handle); private static native void nativeDestroySensorEventQueue(int eventQ); private static native int nativeFlushSensor(int eventQ, int handle); private int nSensorEventQueue; private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); Loading @@ -225,7 +243,8 @@ public class SystemSensorManager extends SensorManager { dispose(false); } public boolean addSensor(Sensor sensor, int delay) { public boolean addSensor( Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) { // Check if already present. int handle = sensor.getHandle(); if (mActiveSensors.get(handle)) return false; Loading @@ -233,10 +252,14 @@ public class SystemSensorManager extends SensorManager { // Get ready to receive events before calling enable. mActiveSensors.put(handle, true); addSensorEvent(sensor); if (enableSensor(sensor, delay) != 0) { if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) { // Try continuous mode if batching fails. if (maxBatchReportLatencyUs == 0 || maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) { removeSensor(sensor, false); return false; } } return true; } Loading Loading @@ -268,6 +291,12 @@ public class SystemSensorManager extends SensorManager { return false; } public int flushSensor(Sensor sensor) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); return nativeFlushSensor(nSensorEventQueue, sensor.getHandle()); } public boolean hasSensors() { // no more sensors are set return mActiveSensors.indexOfValue(true) >= 0; Loading Loading @@ -295,11 +324,14 @@ public class SystemSensorManager extends SensorManager { } } private int enableSensor(Sensor sensor, int us) { private int enableSensor( Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us); return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs, maxBatchReportLatencyUs, reservedFlags); } private int disableSensor(Sensor sensor) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); Loading @@ -307,6 +339,7 @@ public class SystemSensorManager extends SensorManager { } protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp); protected abstract void dispatchFlushCompleteEvent(int handle); protected abstract void addSensorEvent(Sensor sensor); protected abstract void removeSensorEvent(Sensor sensor); Loading @@ -314,12 +347,14 @@ public class SystemSensorManager extends SensorManager { static final class SensorEventQueue extends BaseEventQueue { private final SensorEventListener mListener; private final FlushCompleteListener mFlushCompleteListener; private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>(); public SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager) { SystemSensorManager manager, FlushCompleteListener flushCompleteListener) { super(looper, manager); mListener = listener; mFlushCompleteListener = flushCompleteListener; } public void addSensorEvent(Sensor sensor) { Loading Loading @@ -370,6 +405,15 @@ public class SystemSensorManager extends SensorManager { } mListener.onSensorChanged(t); } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { final Sensor sensor = sHandleToSensor.get(handle); if (mFlushCompleteListener != null) { mFlushCompleteListener.onFlushCompleted(sensor); } return; } } static final class TriggerEventQueue extends BaseEventQueue { Loading Loading @@ -415,5 +459,35 @@ public class SystemSensorManager extends SensorManager { mListener.onTrigger(t); } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { } } static final class FlushEventQueue extends BaseEventQueue { public FlushEventQueue(Looper looper, SystemSensorManager manager) { super(looper, manager); } @SuppressWarnings("unused") @Override protected void dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp) { } @Override @SuppressWarnings("unused") protected void addSensorEvent(Sensor sensor) { } @Override @SuppressWarnings("unused") protected void removeSensorEvent(Sensor sensor) { } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { } } }
core/jni/android_hardware_SensorManager.cpp +41 −11 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ static struct { jclass clazz; jmethodID dispatchSensorEvent; jmethodID dispatchFlushCompleteEvent; } gBaseEventQueueClassInfo; namespace android { Loading @@ -46,6 +47,8 @@ struct SensorOffsets jfieldID resolution; jfieldID power; jfieldID minDelay; jfieldID fifoReservedEventCount; jfieldID fifoMaxEventCount; } gSensorOffsets; Loading @@ -67,6 +70,9 @@ nativeClassInit (JNIEnv *_env, jclass _this) sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F"); sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F"); sensorOffsets.minDelay = _env->GetFieldID(sensorClass, "mMinDelay", "I"); sensorOffsets.fifoReservedEventCount = _env->GetFieldID(sensorClass, "mFifoReservedEventCount", "I"); sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount", "I"); } static jint Loading @@ -92,7 +98,9 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next) env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution()); env->SetFloatField(sensor, sensorOffsets.power, list->getPowerUsage()); env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay()); env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount, list->getFifoReservedEventCount()); env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount()); next++; return size_t(next) < count ? next : 0; } Loading Loading @@ -150,12 +158,20 @@ private: env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data); } if (buffer[i].type == SENSOR_TYPE_META_DATA) { // This is a flush complete sensor event. Call dispatchFlushCompleteEvent // method. env->CallVoidMethod(mReceiverObject, gBaseEventQueueClassInfo.dispatchFlushCompleteEvent, buffer[i].meta_data.sensor); } else { env->CallVoidMethod(mReceiverObject, gBaseEventQueueClassInfo.dispatchSensorEvent, buffer[i].sensor, mScratch, buffer[i].vector.status, buffer[i].timestamp); } if (env->ExceptionCheck()) { ALOGE("Exception dispatching input event."); Loading Loading @@ -186,9 +202,11 @@ static jint nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ return jint(receiver.get()); } static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint us) { static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint rate_us, jint maxBatchReportLatency, jint reservedFlags) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); return receiver->getSensorEventQueue()->enableSensor(handle, us); return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency, reservedFlags); } static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) { Loading @@ -202,6 +220,10 @@ static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jint eventQ receiver->decStrong((void*)nativeInitSensorEventQueue); } static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); return receiver->getSensorEventQueue()->flushSensor(handle); } //---------------------------------------------------------------------------- Loading @@ -221,7 +243,7 @@ static JNINativeMethod gBaseEventQueueMethods[] = { (void*)nativeInitSensorEventQueue }, {"nativeEnableSensor", "(III)I", "(IIIII)I", (void*)nativeEnableSensor }, {"nativeDisableSensor", Loading @@ -231,6 +253,10 @@ static JNINativeMethod gBaseEventQueueMethods[] = { {"nativeDestroySensorEventQueue", "(I)V", (void*)nativeDestroySensorEventQueue }, {"nativeFlushSensor", "(II)I", (void*)nativeFlushSensor }, }; }; // namespace android Loading Loading @@ -260,5 +286,9 @@ int register_android_hardware_SensorManager(JNIEnv *env) gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V"); GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchFlushCompleteEvent, gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V"); return 0; }