summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt3
-rw-r--r--core/java/android/hardware/Sensor.java18
-rw-r--r--core/java/android/hardware/SensorManager.java100
-rw-r--r--core/java/android/hardware/SystemSensorManager.java112
-rw-r--r--core/jni/android_hardware_SensorManager.cpp33
5 files changed, 254 insertions, 12 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index fed8849..87e130c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -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
@@ -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[]);
@@ -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);
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 39f4cca..e875864 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -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.
@@ -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;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 34b895b..861969e 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -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;
@@ -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) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 7ad3a68..11037fd 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -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;
@@ -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 =
@@ -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) {
@@ -82,6 +88,8 @@ public class SystemSensorManager extends SensorManager {
}
} while (i>0);
}
+ mHasDataInjectionPermissions = context.checkSelfPermission(
+ Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED;
}
}
@@ -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();
@@ -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;
}
@@ -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();
@@ -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;
}
@@ -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;
}
@@ -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) {
+
+ }
+ }
}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 16e5b3c..0cf596c 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -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 {
@@ -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) {
@@ -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);
}
@@ -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);
@@ -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[] = {
@@ -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",
@@ -350,6 +369,10 @@ static JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeFlushSensor",
"(J)I",
(void*)nativeFlushSensor },
+
+ {"nativeInjectSensorData",
+ "(JI[FIJ)I",
+ (void*)nativeInjectSensorData },
};
}; // namespace android