Loading api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -13256,6 +13256,7 @@ package android.hardware { method public int getType(); method public java.lang.String getVendor(); method public int getVersion(); method public boolean isDataInjectionSupported(); method public boolean isWakeUpSensor(); field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0 field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2 Loading Loading @@ -13331,6 +13332,7 @@ package android.hardware { public abstract class SensorManager { method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor); method public boolean enableDataInjectionMode(boolean); method public boolean flush(android.hardware.SensorEventListener); method public static float getAltitude(float, float); method public static void getAngleChange(float[], float[], float[]); Loading @@ -13343,6 +13345,7 @@ package android.hardware { method public static void getRotationMatrixFromVector(float[], float[]); method public java.util.List<android.hardware.Sensor> getSensorList(int); method public deprecated int getSensors(); method public boolean injectSensorData(android.hardware.Sensor, float[], int, long); method public deprecated boolean registerListener(android.hardware.SensorListener, int); method public deprecated boolean registerListener(android.hardware.SensorListener, int, int); method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int); core/java/android/hardware/Sensor.java +18 −0 Original line number Diff line number Diff line Loading @@ -580,6 +580,10 @@ public final class Sensor { private static final int REPORTING_MODE_MASK = 0xE; private static final int REPORTING_MODE_SHIFT = 1; // MASK for LSB fifth bit. Used to know whether the sensor supports data injection or not. private static final int DATA_INJECTION_MASK = 0x10; private static final int DATA_INJECTION_SHIFT = 4; // TODO(): The following arrays are fragile and error-prone. This needs to be refactored. // Note: This needs to be updated, whenever a new sensor is added. Loading Loading @@ -822,6 +826,20 @@ public final class Sensor { return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0; } /** * Returns true if the sensor supports data injection when the * HAL is set to data injection mode. * * @return <code>true</code> if the sensor supports data * injection when the HAL is set in injection mode, * false otherwise. * @hide */ @SystemApi public boolean isDataInjectionSupported() { return (((mFlags & DATA_INJECTION_MASK) >> DATA_INJECTION_SHIFT)) != 0; } void setRange(float max, float res) { mMaxRange = max; mResolution = res; Loading core/java/android/hardware/SensorManager.java +100 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package android.hardware; import android.annotation.SystemApi; import android.os.Build; import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; Loading Loading @@ -1555,6 +1558,103 @@ public abstract class SensorManager { Sensor sensor, boolean disable); /** * For testing purposes only. Not for third party applications. * * Enable data injection mode in sensor service. This mode is * expected to be used only for testing purposes. If the HAL is * set to data injection mode, it will ignore the input from * physical sensors and read sensor data that is injected from * the test application. This mode is used for testing vendor * implementations for various algorithms like Rotation Vector, * Significant Motion, Step Counter etc. * * The tests which call this API need to have {@code * android.permission.HARDWARE_TEST} permission which isn't * available for third party applications. * * @param enable True to set the HAL in DATA_INJECTION mode. * False to reset the HAL back to NORMAL mode. * * @return true if the HAL supports data injection and false * otherwise. * @hide */ @SystemApi public boolean enableDataInjectionMode(boolean enable) { return enableDataInjectionImpl(enable); } /** * @hide */ protected abstract boolean enableDataInjectionImpl(boolean enable); /** * For testing purposes only. Not for third party applications. * * This method is used to inject raw sensor data into the HAL. * Call enableDataInjection before this method to set the HAL in * data injection mode. This method should be called only if a * previous call to enableDataInjection has been successful and * the HAL is already in data injection mode. * * The tests which call this API need to have {@code * android.permission.HARDWARE_TEST} permission which isn't * available for third party applications. * * @param sensor The sensor to inject. * @param values Sensor values to inject. The length of this * array must be exactly equal to the number of * values reported by the sensor type. * @param accuracy Accuracy of the sensor. * @param timestamp Sensor timestamp associated with the event. * * @return boolean True if the data injection succeeds, false * otherwise. * @throws IllegalArgumentException when the sensor is null, * data injection is not supported by the sensor, values * are null, incorrect number of values for the sensor, * sensor accuracy is incorrect or timestamps are * invalid. * @hide */ @SystemApi public boolean injectSensorData(Sensor sensor, float[] values, int accuracy, long timestamp) { if (sensor == null) { throw new IllegalArgumentException("sensor cannot be null"); } if (!sensor.isDataInjectionSupported()) { throw new IllegalArgumentException("sensor does not support data injection"); } if (values == null) { throw new IllegalArgumentException("sensor data cannot be null"); } int expectedNumValues = Sensor.getMaxLengthValuesArray(sensor, Build.VERSION_CODES.MNC); if (values.length != expectedNumValues) { throw new IllegalArgumentException ("Wrong number of values for sensor " + sensor.getName() + " actual=" + values.length + " expected=" + expectedNumValues); } if (accuracy < SENSOR_STATUS_NO_CONTACT || accuracy > SENSOR_STATUS_ACCURACY_HIGH) { throw new IllegalArgumentException("Invalid sensor accuracy"); } if (timestamp <= 0) { throw new IllegalArgumentException("Negative or zero sensor timestamp"); } if (timestamp > SystemClock.elapsedRealtimeNanos()) { throw new IllegalArgumentException("Sensor timestamp into the future"); } return injectSensorDataImpl(sensor, values, accuracy, timestamp); } /** * @hide */ protected abstract boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp); private LegacySensorManager getLegacySensorManager() { synchronized (mSensorListByType) { if (mLegacySensorManager == null) { Loading core/java/android/hardware/SystemSensorManager.java +105 −7 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package android.hardware; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; Loading @@ -40,11 +42,14 @@ import java.util.List; public class SystemSensorManager extends SensorManager { private static native void nativeClassInit(); private static native int nativeGetNextSensor(Sensor sensor, int next); private static native int nativeEnableDataInjection(boolean enable); private static boolean sSensorModuleInitialized = false; private static final Object sSensorModuleLock = new Object(); private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>(); private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>(); private static InjectEventQueue mInjectEventQueue = null; private static boolean mDataInjectionMode = false; // Listener list private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners = Loading @@ -56,6 +61,7 @@ public class SystemSensorManager extends SensorManager { private final Looper mMainLooper; private final int mTargetSdkLevel; private final String mPackageName; private final boolean mHasDataInjectionPermissions; /** {@hide} */ public SystemSensorManager(Context context, Looper mainLooper) { Loading @@ -82,6 +88,8 @@ public class SystemSensorManager extends SensorManager { } } while (i>0); } mHasDataInjectionPermissions = context.checkSelfPermission( Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED; } } Loading Loading @@ -219,19 +227,72 @@ public class SystemSensorManager extends SensorManager { } } protected boolean enableDataInjectionImpl(boolean enable) { if (!mHasDataInjectionPermissions) { throw new SecurityException("Permission denial. Calling enableDataInjection without " + Manifest.permission.HARDWARE_TEST); } synchronized (sSensorModuleLock) { int ret = nativeEnableDataInjection(enable); // The HAL does not support injection. Ignore. if (ret != 0) { Log.e(TAG, "HAL does not support data injection"); return false; } mDataInjectionMode = enable; // If data injection is being disabled clean up the native resources. if (!enable && mInjectEventQueue != null) { mInjectEventQueue.dispose(); mInjectEventQueue = null; } return true; } } protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp) { if (!mHasDataInjectionPermissions) { throw new SecurityException("Permission denial. Calling injectSensorData without " + Manifest.permission.HARDWARE_TEST); } synchronized (sSensorModuleLock) { if (!mDataInjectionMode) { Log.e(TAG, "Data injection mode not activated before calling injectSensorData"); return false; } if (mInjectEventQueue == null) { mInjectEventQueue = new InjectEventQueue(mMainLooper, this); } int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy, timestamp); // If there are any errors in data injection clean up the native resources. if (ret != 0) { mInjectEventQueue.dispose(); mInjectEventQueue = null; mDataInjectionMode = false; } return ret == 0; } } /* * BaseEventQueue is the communication channel with the sensor service, * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between * the queues and the listeners. * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case * where data is being injected into the sensor HAL through the sensor service. It is not * associated with any listener and there is one InjectEventQueue associated with a * SensorManager instance. */ private static abstract class BaseEventQueue { private native long nativeInitBaseEventQueue(WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch, String packageName); MessageQueue msgQ, float[] scratch, String packageName, int mode); private static native int nativeEnableSensor(long eventQ, int handle, int rateUs, int maxBatchReportLatencyUs); private static native int nativeDisableSensor(long eventQ, int handle); private static native void nativeDestroySensorEventQueue(long eventQ); private static native int nativeFlushSensor(long eventQ); private static native int nativeInjectSensorData(long eventQ, int handle, float[] values,int accuracy, long timestamp); private long nSensorEventQueue; private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); Loading @@ -240,10 +301,12 @@ public class SystemSensorManager extends SensorManager { private final float[] mScratch = new float[16]; protected final SystemSensorManager mManager; BaseEventQueue(Looper looper, SystemSensorManager manager) { protected static final int OPERATING_MODE_NORMAL = 0; protected static final int OPERATING_MODE_DATA_INJECTION = 1; BaseEventQueue(Looper looper, SystemSensorManager manager, int mode) { nSensorEventQueue = nativeInitBaseEventQueue(new WeakReference<BaseEventQueue>(this), looper.getQueue(), mScratch, manager.mPackageName); looper.getQueue(), mScratch, manager.mPackageName, mode); mCloseGuard.open("dispose"); mManager = manager; } Loading Loading @@ -340,6 +403,11 @@ public class SystemSensorManager extends SensorManager { maxBatchReportLatencyUs); } protected int injectSensorDataBase(int handle, float[] values, int accuracy, long timestamp) { return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp); } private int disableSensor(Sensor sensor) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); Loading @@ -359,7 +427,7 @@ public class SystemSensorManager extends SensorManager { public SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager) { super(looper, manager); super(looper, manager, OPERATING_MODE_NORMAL); mListener = listener; } Loading Loading @@ -426,7 +494,7 @@ public class SystemSensorManager extends SensorManager { public TriggerEventQueue(TriggerEventListener listener, Looper looper, SystemSensorManager manager) { super(looper, manager); super(looper, manager, OPERATING_MODE_NORMAL); mListener = listener; } Loading Loading @@ -477,4 +545,34 @@ public class SystemSensorManager extends SensorManager { protected void dispatchFlushCompleteEvent(int handle) { } } static final class InjectEventQueue extends BaseEventQueue { public InjectEventQueue(Looper looper, SystemSensorManager manager) { super(looper, manager, OPERATING_MODE_DATA_INJECTION); } int injectSensorData(int handle, float[] values,int accuracy, long timestamp) { return injectSensorDataBase(handle, values, accuracy, timestamp); } @SuppressWarnings("unused") protected void dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp) { } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { } @SuppressWarnings("unused") protected void addSensorEvent(Sensor sensor) { } @SuppressWarnings("unused") protected void removeSensorEvent(Sensor sensor) { } } } core/jni/android_hardware_SensorManager.cpp +28 −5 Original line number Diff line number Diff line Loading @@ -174,6 +174,11 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next) return size_t(next) < count ? next : 0; } static int nativeEnableDataInjection(JNIEnv *_env, jclass _this, jboolean enable) { SensorManager& mgr(SensorManager::getInstance()); return mgr.enableDataInjection(enable); } //---------------------------------------------------------------------------- class Receiver : public LooperCallback { Loading Loading @@ -277,11 +282,11 @@ private: }; static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQWeak, jobject msgQ, jfloatArray scratch, jstring packageName) { jfloatArray scratch, jstring packageName, jint mode) { SensorManager& mgr(SensorManager::getInstance()); ScopedUtfChars packageUtf(env, packageName); String8 clientName(packageUtf.c_str()); sp<SensorEventQueue> queue(mgr.createEventQueue(clientName)); sp<SensorEventQueue> queue(mgr.createEventQueue(clientName, mode)); sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ); if (messageQueue == NULL) { Loading @@ -297,7 +302,6 @@ static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject event static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us, jint maxBatchReportLatency) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency, 0); } Loading @@ -307,7 +311,7 @@ static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint ha return receiver->getSensorEventQueue()->disableSensor(handle); } static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) { static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); receiver->destroy(); receiver->decStrong((void*)nativeInitSensorEventQueue); Loading @@ -318,6 +322,17 @@ static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) { return receiver->getSensorEventQueue()->flush(); } static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jfloatArray values, jint accuracy, jlong timestamp) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); // Create a sensor_event from the above data which can be injected into the HAL. ASensorEvent sensor_event; memset(&sensor_event, 0, sizeof(sensor_event)); sensor_event.sensor = handle; sensor_event.timestamp = timestamp; env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data); return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event); } //---------------------------------------------------------------------------- static JNINativeMethod gSystemSensorManagerMethods[] = { Loading @@ -328,11 +343,15 @@ static JNINativeMethod gSystemSensorManagerMethods[] = { {"nativeGetNextSensor", "(Landroid/hardware/Sensor;I)I", (void*)nativeGetNextSensor }, {"nativeEnableDataInjection", "(Z)I", (void*)nativeEnableDataInjection }, }; static JNINativeMethod gBaseEventQueueMethods[] = { {"nativeInitBaseEventQueue", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;)J", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;I)J", (void*)nativeInitSensorEventQueue }, {"nativeEnableSensor", Loading @@ -350,6 +369,10 @@ static JNINativeMethod gBaseEventQueueMethods[] = { {"nativeFlushSensor", "(J)I", (void*)nativeFlushSensor }, {"nativeInjectSensorData", "(JI[FIJ)I", (void*)nativeInjectSensorData }, }; }; // namespace android Loading Loading
api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -13256,6 +13256,7 @@ package android.hardware { method public int getType(); method public java.lang.String getVendor(); method public int getVersion(); method public boolean isDataInjectionSupported(); method public boolean isWakeUpSensor(); field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0 field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2 Loading Loading @@ -13331,6 +13332,7 @@ package android.hardware { public abstract class SensorManager { method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor); method public boolean enableDataInjectionMode(boolean); method public boolean flush(android.hardware.SensorEventListener); method public static float getAltitude(float, float); method public static void getAngleChange(float[], float[], float[]); Loading @@ -13343,6 +13345,7 @@ package android.hardware { method public static void getRotationMatrixFromVector(float[], float[]); method public java.util.List<android.hardware.Sensor> getSensorList(int); method public deprecated int getSensors(); method public boolean injectSensorData(android.hardware.Sensor, float[], int, long); method public deprecated boolean registerListener(android.hardware.SensorListener, int); method public deprecated boolean registerListener(android.hardware.SensorListener, int, int); method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
core/java/android/hardware/Sensor.java +18 −0 Original line number Diff line number Diff line Loading @@ -580,6 +580,10 @@ public final class Sensor { private static final int REPORTING_MODE_MASK = 0xE; private static final int REPORTING_MODE_SHIFT = 1; // MASK for LSB fifth bit. Used to know whether the sensor supports data injection or not. private static final int DATA_INJECTION_MASK = 0x10; private static final int DATA_INJECTION_SHIFT = 4; // TODO(): The following arrays are fragile and error-prone. This needs to be refactored. // Note: This needs to be updated, whenever a new sensor is added. Loading Loading @@ -822,6 +826,20 @@ public final class Sensor { return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0; } /** * Returns true if the sensor supports data injection when the * HAL is set to data injection mode. * * @return <code>true</code> if the sensor supports data * injection when the HAL is set in injection mode, * false otherwise. * @hide */ @SystemApi public boolean isDataInjectionSupported() { return (((mFlags & DATA_INJECTION_MASK) >> DATA_INJECTION_SHIFT)) != 0; } void setRange(float max, float res) { mMaxRange = max; mResolution = res; Loading
core/java/android/hardware/SensorManager.java +100 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package android.hardware; import android.annotation.SystemApi; import android.os.Build; import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; Loading Loading @@ -1555,6 +1558,103 @@ public abstract class SensorManager { Sensor sensor, boolean disable); /** * For testing purposes only. Not for third party applications. * * Enable data injection mode in sensor service. This mode is * expected to be used only for testing purposes. If the HAL is * set to data injection mode, it will ignore the input from * physical sensors and read sensor data that is injected from * the test application. This mode is used for testing vendor * implementations for various algorithms like Rotation Vector, * Significant Motion, Step Counter etc. * * The tests which call this API need to have {@code * android.permission.HARDWARE_TEST} permission which isn't * available for third party applications. * * @param enable True to set the HAL in DATA_INJECTION mode. * False to reset the HAL back to NORMAL mode. * * @return true if the HAL supports data injection and false * otherwise. * @hide */ @SystemApi public boolean enableDataInjectionMode(boolean enable) { return enableDataInjectionImpl(enable); } /** * @hide */ protected abstract boolean enableDataInjectionImpl(boolean enable); /** * For testing purposes only. Not for third party applications. * * This method is used to inject raw sensor data into the HAL. * Call enableDataInjection before this method to set the HAL in * data injection mode. This method should be called only if a * previous call to enableDataInjection has been successful and * the HAL is already in data injection mode. * * The tests which call this API need to have {@code * android.permission.HARDWARE_TEST} permission which isn't * available for third party applications. * * @param sensor The sensor to inject. * @param values Sensor values to inject. The length of this * array must be exactly equal to the number of * values reported by the sensor type. * @param accuracy Accuracy of the sensor. * @param timestamp Sensor timestamp associated with the event. * * @return boolean True if the data injection succeeds, false * otherwise. * @throws IllegalArgumentException when the sensor is null, * data injection is not supported by the sensor, values * are null, incorrect number of values for the sensor, * sensor accuracy is incorrect or timestamps are * invalid. * @hide */ @SystemApi public boolean injectSensorData(Sensor sensor, float[] values, int accuracy, long timestamp) { if (sensor == null) { throw new IllegalArgumentException("sensor cannot be null"); } if (!sensor.isDataInjectionSupported()) { throw new IllegalArgumentException("sensor does not support data injection"); } if (values == null) { throw new IllegalArgumentException("sensor data cannot be null"); } int expectedNumValues = Sensor.getMaxLengthValuesArray(sensor, Build.VERSION_CODES.MNC); if (values.length != expectedNumValues) { throw new IllegalArgumentException ("Wrong number of values for sensor " + sensor.getName() + " actual=" + values.length + " expected=" + expectedNumValues); } if (accuracy < SENSOR_STATUS_NO_CONTACT || accuracy > SENSOR_STATUS_ACCURACY_HIGH) { throw new IllegalArgumentException("Invalid sensor accuracy"); } if (timestamp <= 0) { throw new IllegalArgumentException("Negative or zero sensor timestamp"); } if (timestamp > SystemClock.elapsedRealtimeNanos()) { throw new IllegalArgumentException("Sensor timestamp into the future"); } return injectSensorDataImpl(sensor, values, accuracy, timestamp); } /** * @hide */ protected abstract boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp); private LegacySensorManager getLegacySensorManager() { synchronized (mSensorListByType) { if (mLegacySensorManager == null) { Loading
core/java/android/hardware/SystemSensorManager.java +105 −7 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package android.hardware; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; Loading @@ -40,11 +42,14 @@ import java.util.List; public class SystemSensorManager extends SensorManager { private static native void nativeClassInit(); private static native int nativeGetNextSensor(Sensor sensor, int next); private static native int nativeEnableDataInjection(boolean enable); private static boolean sSensorModuleInitialized = false; private static final Object sSensorModuleLock = new Object(); private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>(); private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>(); private static InjectEventQueue mInjectEventQueue = null; private static boolean mDataInjectionMode = false; // Listener list private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners = Loading @@ -56,6 +61,7 @@ public class SystemSensorManager extends SensorManager { private final Looper mMainLooper; private final int mTargetSdkLevel; private final String mPackageName; private final boolean mHasDataInjectionPermissions; /** {@hide} */ public SystemSensorManager(Context context, Looper mainLooper) { Loading @@ -82,6 +88,8 @@ public class SystemSensorManager extends SensorManager { } } while (i>0); } mHasDataInjectionPermissions = context.checkSelfPermission( Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED; } } Loading Loading @@ -219,19 +227,72 @@ public class SystemSensorManager extends SensorManager { } } protected boolean enableDataInjectionImpl(boolean enable) { if (!mHasDataInjectionPermissions) { throw new SecurityException("Permission denial. Calling enableDataInjection without " + Manifest.permission.HARDWARE_TEST); } synchronized (sSensorModuleLock) { int ret = nativeEnableDataInjection(enable); // The HAL does not support injection. Ignore. if (ret != 0) { Log.e(TAG, "HAL does not support data injection"); return false; } mDataInjectionMode = enable; // If data injection is being disabled clean up the native resources. if (!enable && mInjectEventQueue != null) { mInjectEventQueue.dispose(); mInjectEventQueue = null; } return true; } } protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp) { if (!mHasDataInjectionPermissions) { throw new SecurityException("Permission denial. Calling injectSensorData without " + Manifest.permission.HARDWARE_TEST); } synchronized (sSensorModuleLock) { if (!mDataInjectionMode) { Log.e(TAG, "Data injection mode not activated before calling injectSensorData"); return false; } if (mInjectEventQueue == null) { mInjectEventQueue = new InjectEventQueue(mMainLooper, this); } int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy, timestamp); // If there are any errors in data injection clean up the native resources. if (ret != 0) { mInjectEventQueue.dispose(); mInjectEventQueue = null; mDataInjectionMode = false; } return ret == 0; } } /* * BaseEventQueue is the communication channel with the sensor service, * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between * the queues and the listeners. * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case * where data is being injected into the sensor HAL through the sensor service. It is not * associated with any listener and there is one InjectEventQueue associated with a * SensorManager instance. */ private static abstract class BaseEventQueue { private native long nativeInitBaseEventQueue(WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch, String packageName); MessageQueue msgQ, float[] scratch, String packageName, int mode); private static native int nativeEnableSensor(long eventQ, int handle, int rateUs, int maxBatchReportLatencyUs); private static native int nativeDisableSensor(long eventQ, int handle); private static native void nativeDestroySensorEventQueue(long eventQ); private static native int nativeFlushSensor(long eventQ); private static native int nativeInjectSensorData(long eventQ, int handle, float[] values,int accuracy, long timestamp); private long nSensorEventQueue; private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); Loading @@ -240,10 +301,12 @@ public class SystemSensorManager extends SensorManager { private final float[] mScratch = new float[16]; protected final SystemSensorManager mManager; BaseEventQueue(Looper looper, SystemSensorManager manager) { protected static final int OPERATING_MODE_NORMAL = 0; protected static final int OPERATING_MODE_DATA_INJECTION = 1; BaseEventQueue(Looper looper, SystemSensorManager manager, int mode) { nSensorEventQueue = nativeInitBaseEventQueue(new WeakReference<BaseEventQueue>(this), looper.getQueue(), mScratch, manager.mPackageName); looper.getQueue(), mScratch, manager.mPackageName, mode); mCloseGuard.open("dispose"); mManager = manager; } Loading Loading @@ -340,6 +403,11 @@ public class SystemSensorManager extends SensorManager { maxBatchReportLatencyUs); } protected int injectSensorDataBase(int handle, float[] values, int accuracy, long timestamp) { return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp); } private int disableSensor(Sensor sensor) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); Loading @@ -359,7 +427,7 @@ public class SystemSensorManager extends SensorManager { public SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager) { super(looper, manager); super(looper, manager, OPERATING_MODE_NORMAL); mListener = listener; } Loading Loading @@ -426,7 +494,7 @@ public class SystemSensorManager extends SensorManager { public TriggerEventQueue(TriggerEventListener listener, Looper looper, SystemSensorManager manager) { super(looper, manager); super(looper, manager, OPERATING_MODE_NORMAL); mListener = listener; } Loading Loading @@ -477,4 +545,34 @@ public class SystemSensorManager extends SensorManager { protected void dispatchFlushCompleteEvent(int handle) { } } static final class InjectEventQueue extends BaseEventQueue { public InjectEventQueue(Looper looper, SystemSensorManager manager) { super(looper, manager, OPERATING_MODE_DATA_INJECTION); } int injectSensorData(int handle, float[] values,int accuracy, long timestamp) { return injectSensorDataBase(handle, values, accuracy, timestamp); } @SuppressWarnings("unused") protected void dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp) { } @SuppressWarnings("unused") protected void dispatchFlushCompleteEvent(int handle) { } @SuppressWarnings("unused") protected void addSensorEvent(Sensor sensor) { } @SuppressWarnings("unused") protected void removeSensorEvent(Sensor sensor) { } } }
core/jni/android_hardware_SensorManager.cpp +28 −5 Original line number Diff line number Diff line Loading @@ -174,6 +174,11 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next) return size_t(next) < count ? next : 0; } static int nativeEnableDataInjection(JNIEnv *_env, jclass _this, jboolean enable) { SensorManager& mgr(SensorManager::getInstance()); return mgr.enableDataInjection(enable); } //---------------------------------------------------------------------------- class Receiver : public LooperCallback { Loading Loading @@ -277,11 +282,11 @@ private: }; static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQWeak, jobject msgQ, jfloatArray scratch, jstring packageName) { jfloatArray scratch, jstring packageName, jint mode) { SensorManager& mgr(SensorManager::getInstance()); ScopedUtfChars packageUtf(env, packageName); String8 clientName(packageUtf.c_str()); sp<SensorEventQueue> queue(mgr.createEventQueue(clientName)); sp<SensorEventQueue> queue(mgr.createEventQueue(clientName, mode)); sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ); if (messageQueue == NULL) { Loading @@ -297,7 +302,6 @@ static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject event static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us, jint maxBatchReportLatency) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency, 0); } Loading @@ -307,7 +311,7 @@ static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint ha return receiver->getSensorEventQueue()->disableSensor(handle); } static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) { static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); receiver->destroy(); receiver->decStrong((void*)nativeInitSensorEventQueue); Loading @@ -318,6 +322,17 @@ static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) { return receiver->getSensorEventQueue()->flush(); } static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jfloatArray values, jint accuracy, jlong timestamp) { sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ)); // Create a sensor_event from the above data which can be injected into the HAL. ASensorEvent sensor_event; memset(&sensor_event, 0, sizeof(sensor_event)); sensor_event.sensor = handle; sensor_event.timestamp = timestamp; env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data); return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event); } //---------------------------------------------------------------------------- static JNINativeMethod gSystemSensorManagerMethods[] = { Loading @@ -328,11 +343,15 @@ static JNINativeMethod gSystemSensorManagerMethods[] = { {"nativeGetNextSensor", "(Landroid/hardware/Sensor;I)I", (void*)nativeGetNextSensor }, {"nativeEnableDataInjection", "(Z)I", (void*)nativeEnableDataInjection }, }; static JNINativeMethod gBaseEventQueueMethods[] = { {"nativeInitBaseEventQueue", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;)J", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;I)J", (void*)nativeInitSensorEventQueue }, {"nativeEnableSensor", Loading @@ -350,6 +369,10 @@ static JNINativeMethod gBaseEventQueueMethods[] = { {"nativeFlushSensor", "(J)I", (void*)nativeFlushSensor }, {"nativeInjectSensorData", "(JI[FIJ)I", (void*)nativeInjectSensorData }, }; }; // namespace android Loading