package biz.bokhorst.xprivacy;
import java.util.ArrayList;
import java.util.List;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.util.Log;
public class XSensorManager extends XHook {
private Methods mMethod;
private String mClassName;
private static final String cClassName = "android.hardware.SensorManager";
private static final int cMaxRateUs = (int) (0.01 * 1000 * 1000); // 100 Hz
private XSensorManager(Methods method, String restrictionName, String className) {
super(restrictionName, method.name(), null);
mMethod = method;
mClassName = className;
}
public String getClassName() {
return mClassName;
}
// @formatter:off
// public Sensor getDefaultSensor(int type)
// public List<Sensor> getSensorList(int type)
// boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, int maxBatchReportLatencyUs)
// boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, Handler handler)
// boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, int maxBatchReportLatencyUs, Handler handler)
// boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs)
// frameworks/base/core/java/android/hardware/SensorManager.java
// http://developer.android.com/reference/android/hardware/SensorManager.html
// http://developer.android.com/reference/android/hardware/Sensor.html
// @formatter:on
private enum Methods {
getDefaultSensor, getSensorList, registerListener
};
public static List<XHook> getInstances(String className, boolean server) {
List<XHook> listHook = new ArrayList<XHook>();
if (!cClassName.equals(className)) {
if (className == null)
className = cClassName;
listHook.add(new XSensorManager(Methods.getDefaultSensor, PrivacyManager.cSensors, className));
listHook.add(new XSensorManager(Methods.getSensorList, PrivacyManager.cSensors, className));
listHook.add(new XSensorManager(Methods.registerListener, PrivacyManager.cSensors, className));
}
return listHook;
}
@Override
protected void before(XParam param) throws Throwable {
switch (mMethod) {
case getDefaultSensor:
if (isRestricted(param))
param.setResult(null);
else if (param.args.length > 0 && param.args[0] instanceof Integer)
if (isRestricted(param, (Integer) param.args[0]))
param.setResult(null);
break;
case getSensorList:
if (isRestricted(param))
param.setResult(new ArrayList<Sensor>());
else if (param.args.length > 0 && param.args[0] instanceof Integer)
if (isRestricted(param, (Integer) param.args[0]))
param.setResult(new ArrayList<Sensor>());
break;
case registerListener:
if (param.args.length > 2 && param.args[1] instanceof Sensor && param.args[2] instanceof Integer) {
int type = ((Sensor) param.args[1]).getType();
if (type == Sensor.TYPE_GYROSCOPE || type == Sensor.TYPE_GYROSCOPE_UNCALIBRATED) {
int rateUs = (Integer) param.args[2];
// http://developer.android.com/guide/topics/sensors/sensors_overview.html
if (rateUs == SensorManager.SENSOR_DELAY_NORMAL)
return; // 200,000 us
else if (rateUs == SensorManager.SENSOR_DELAY_UI)
return; // 60,000 us
else if (rateUs == SensorManager.SENSOR_DELAY_GAME)
return; // 20,000 us
else if (rateUs == SensorManager.SENSOR_DELAY_FASTEST)
; // 0 us
if (rateUs < cMaxRateUs) // 10,000 us
if (isRestricted(param))
param.args[2] = cMaxRateUs;
}
}
break;
}
}
@Override
@SuppressWarnings("unchecked")
protected void after(XParam param) throws Throwable {
switch (mMethod) {
case getDefaultSensor:
case registerListener:
// Do nothing
break;
case getSensorList:
if (param.getResult() != null && param.args.length > 0 && param.args[0] instanceof Integer)
if ((Integer) param.args[0] == Sensor.TYPE_ALL) {
List<Sensor> listSensor = new ArrayList<Sensor>();
for (Sensor sensor : (List<Sensor>) param.getResult())
if (!isRestricted(param, sensor.getType()))
listSensor.add(sensor);
param.setResult(listSensor);
}
break;
}
}
@SuppressWarnings("deprecation")
private boolean isRestricted(XParam param, int type) throws Throwable {
if (type == Sensor.TYPE_ALL)
return false;
else if (type == Sensor.TYPE_ACCELEROMETER || type == Sensor.TYPE_LINEAR_ACCELERATION) {
if (isRestricted(param, "acceleration"))
return true;
} else if (type == Sensor.TYPE_GRAVITY) {
if (isRestricted(param, "gravity"))
return true;
} else if (type == Sensor.TYPE_RELATIVE_HUMIDITY) {
if (isRestricted(param, "humidity"))
return true;
} else if (type == Sensor.TYPE_LIGHT) {
if (isRestricted(param, "light"))
return true;
} else if (type == Sensor.TYPE_MAGNETIC_FIELD || type == Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED) {
if (isRestricted(param, "magnetic"))
return true;
} else if (type == Sensor.TYPE_SIGNIFICANT_MOTION) {
if (isRestricted(param, "motion"))
return true;
} else if (type == Sensor.TYPE_ORIENTATION || type == Sensor.TYPE_GYROSCOPE
|| type == Sensor.TYPE_GYROSCOPE_UNCALIBRATED) {
if (isRestricted(param, "orientation"))
return true;
} else if (type == Sensor.TYPE_PRESSURE) {
if (isRestricted(param, "pressure"))
return true;
} else if (type == Sensor.TYPE_PROXIMITY) {
if (isRestricted(param, "proximity"))
return true;
} else if (type == Sensor.TYPE_GAME_ROTATION_VECTOR || type == Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR
|| type == Sensor.TYPE_ROTATION_VECTOR) {
if (isRestricted(param, "rotation"))
return true;
} else if (type == Sensor.TYPE_TEMPERATURE || type == Sensor.TYPE_AMBIENT_TEMPERATURE) {
if (isRestricted(param, "temperature"))
return true;
} else if (type == Sensor.TYPE_STEP_COUNTER || type == Sensor.TYPE_STEP_DETECTOR) {
if (isRestricted(param, "step"))
return true;
} else if (type == Sensor.TYPE_HEART_RATE) {
if (isRestricted(param, "heartrate"))
return true;
} else if (type == 22) {
// 22 = TYPE_TILT_DETECTOR
// Do nothing
} else if (type == 23 || type == 24 || type == 25) {
// 23 = TYPE_WAKE_GESTURE
// 24 = TYPE_GLANCE_GESTURE
// 25 = TYPE_PICK_UP_GESTURE
// 23/24 This sensor is expected to only be used by the system ui
// 25 Expected to be used internally for always on display
} else
Util.log(this, Log.WARN, "Unknown sensor type=" + type);
return false;
}
}