import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
public class TiltSensor implements SensorEventListener {
private boolean needsRecalc = false;
private float[] tilt_data = { 0, 0, 0 }, accelerometer = { 0, 0, 0 }, magnetic_field = { 0, 0, 0 }, old_acc = { 0, 0, 0 }, dampened_acc = { 0, 0, 0 };
private boolean tiltAvailble = false;
private final SensorManager man;
final Sensor mag_sensor;
final Sensor acc_sensor;
boolean has_mag;
boolean has_acc;
// Change this to make the sensors respond quicker, or slower:
private static final int delay = SensorManager.SENSOR_DELAY_GAME;
//Call this from your activity to hook listeners if the were removed in pause()
public void resume() {
has_mag = man.registerListener(this, mag_sensor, delay);
has_acc = man.registerListener(this, acc_sensor, delay);
if (!has_mag && !has_acc) {
pause();
}
}
//Call this from your activity to save battery while app is not in foreground
public void pause() {
man.unregisterListener(this);
}
// Special class used to handle sensor events:
@Override
public void onSensorChanged(SensorEvent e) {
final float[] vals = e.values;
final int type = e.sensor.getType();
switch (type) {
case (Sensor.TYPE_ACCELEROMETER): {
needsRecalc = true;
if (!has_mag) {
System.
arraycopy(accelerometer,
0, old_acc,
0,
3); }
System.
arraycopy(vals,
0, accelerometer,
0,
3); if (!has_mag) {
for (int i = 0; i < 3; i++) {
//Accumulate changes
final float sensitivity = 0.08f;
dampened_acc[i] += (accelerometer[i] - old_acc[i]) * sensitivity;
//Even out drift over time
dampened_acc[i] *= 0.99;
}
}
}
break;
case (Sensor.TYPE_MAGNETIC_FIELD): {
needsRecalc = true;
System.
arraycopy(vals,
0, magnetic_field,
0,
3); }
break;
}
}
@Override
public void onAccuracyChanged(Sensor event, int res) {
}
// The constructor will use a context object to register itself for various inputs:
man
= (SensorManager
) c.
getSystemService(Context.
SENSOR_SERVICE); mag_sensor = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
acc_sensor = man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//Sensor gyr_sensor = man.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
resume();
if (has_acc) {
tiltAvailble = true;
if (has_mag) {
Log.d("TiltCalc", "Using accelerometer + compass.");
}
else {
Log.d("TiltCalc", "Using only accelerometer.");
}
}
else {
tiltAvailble = false;
Log.d("TiltCalc", "No acceptable hardware found, tilt not available.");
//No use in having listeners registered
pause();
}
}
@Override
pause();
super.finalize();
}
public boolean isTiltAbailable() {
return tiltAvailble;
}
// Will return the most up-to-date tilt data in the vals[] array
public void getTilt(float[] vals) {
// If some of the data has been changed, then we need to recalculate some things...
if (needsRecalc) {
if (has_acc) {
if (has_mag) {
float[] R = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// Calculate the rotation matrix, and use that to get the orientation:
if (SensorManager.getRotationMatrix(R, null, accelerometer, magnetic_field)) {
SensorManager.getOrientation(R, tilt_data);
}
}
//Cheat by assuming user will be holding device in a certain way.
else {
tilt_data[1] = dampened_acc[0];
}
}
needsRecalc = false;
}
System.
arraycopy(tilt_data,
0, vals,
0,
3); }
}
aW1wb3J0IGFuZHJvaWQuY29udGVudC5Db250ZXh0OwppbXBvcnQgYW5kcm9pZC5oYXJkd2FyZS5TZW5zb3I7CmltcG9ydCBhbmRyb2lkLmhhcmR3YXJlLlNlbnNvckV2ZW50OwppbXBvcnQgYW5kcm9pZC5oYXJkd2FyZS5TZW5zb3JFdmVudExpc3RlbmVyOwppbXBvcnQgYW5kcm9pZC5oYXJkd2FyZS5TZW5zb3JNYW5hZ2VyOwppbXBvcnQgYW5kcm9pZC51dGlsLkxvZzsKCnB1YmxpYyBjbGFzcyBUaWx0U2Vuc29yIGltcGxlbWVudHMgU2Vuc29yRXZlbnRMaXN0ZW5lciB7CgogICAgcHJpdmF0ZSBib29sZWFuIG5lZWRzUmVjYWxjID0gZmFsc2U7Cglwcml2YXRlIGZsb2F0W10gdGlsdF9kYXRhID0geyAwLCAwLCAwIH0sIGFjY2VsZXJvbWV0ZXIgPSB7IDAsIDAsIDAgfSwgbWFnbmV0aWNfZmllbGQgPSB7IDAsIDAsIDAgfSwgb2xkX2FjYyA9IHsgMCwgMCwgMCB9LCBkYW1wZW5lZF9hY2MgPSB7IDAsIDAsIDAgfTsKCXByaXZhdGUgYm9vbGVhbiB0aWx0QXZhaWxibGUgPSBmYWxzZTsKCXByaXZhdGUgZmluYWwgU2Vuc29yTWFuYWdlciBtYW47CglmaW5hbCBTZW5zb3IgbWFnX3NlbnNvcjsKCWZpbmFsIFNlbnNvciBhY2Nfc2Vuc29yOwoJYm9vbGVhbiBoYXNfbWFnOwoJYm9vbGVhbiBoYXNfYWNjOwoKCS8vIENoYW5nZSB0aGlzIHRvIG1ha2UgdGhlIHNlbnNvcnMgcmVzcG9uZCBxdWlja2VyLCBvciBzbG93ZXI6Cglwcml2YXRlIHN0YXRpYyBmaW5hbCBpbnQgZGVsYXkgPSBTZW5zb3JNYW5hZ2VyLlNFTlNPUl9ERUxBWV9HQU1FOwoKCS8vQ2FsbCB0aGlzIGZyb20geW91ciBhY3Rpdml0eSB0byBob29rIGxpc3RlbmVycyBpZiB0aGUgd2VyZSByZW1vdmVkIGluIHBhdXNlKCkKCXB1YmxpYyB2b2lkIHJlc3VtZSgpIHsKCQloYXNfbWFnID0gbWFuLnJlZ2lzdGVyTGlzdGVuZXIodGhpcywgbWFnX3NlbnNvciwgZGVsYXkpOwoJCWhhc19hY2MgPSBtYW4ucmVnaXN0ZXJMaXN0ZW5lcih0aGlzLCBhY2Nfc2Vuc29yLCBkZWxheSk7CgkJaWYgKCFoYXNfbWFnICYmICFoYXNfYWNjKSB7CgkJCXBhdXNlKCk7CgkJfQoJfQoKCS8vQ2FsbCB0aGlzIGZyb20geW91ciBhY3Rpdml0eSB0byBzYXZlIGJhdHRlcnkgd2hpbGUgYXBwIGlzIG5vdCBpbiBmb3JlZ3JvdW5kCglwdWJsaWMgdm9pZCBwYXVzZSgpIHsKCQltYW4udW5yZWdpc3Rlckxpc3RlbmVyKHRoaXMpOwoJfQoKCS8vIFNwZWNpYWwgY2xhc3MgdXNlZCB0byBoYW5kbGUgc2Vuc29yIGV2ZW50czoKCUBPdmVycmlkZQoJcHVibGljIHZvaWQgb25TZW5zb3JDaGFuZ2VkKFNlbnNvckV2ZW50IGUpIHsKCQlmaW5hbCBmbG9hdFtdIHZhbHMgPSBlLnZhbHVlczsKCQlmaW5hbCBpbnQgdHlwZSA9IGUuc2Vuc29yLmdldFR5cGUoKTsKCQlzd2l0Y2ggKHR5cGUpIHsKCQkJY2FzZSAoU2Vuc29yLlRZUEVfQUNDRUxFUk9NRVRFUik6IHsKCQkJCW5lZWRzUmVjYWxjID0gdHJ1ZTsKCQkJCWlmICghaGFzX21hZykgewoJCQkJCVN5c3RlbS5hcnJheWNvcHkoYWNjZWxlcm9tZXRlciwgMCwgb2xkX2FjYywgMCwgMyk7CgkJCQl9CgkJCQlTeXN0ZW0uYXJyYXljb3B5KHZhbHMsIDAsIGFjY2VsZXJvbWV0ZXIsIDAsIDMpOwoJCQkJaWYgKCFoYXNfbWFnKSB7CgkJCQkJZm9yIChpbnQgaSA9IDA7IGkgPCAzOyBpKyspIHsKCQkJCQkJLy9BY2N1bXVsYXRlIGNoYW5nZXMKCQkJCQkJZmluYWwgZmxvYXQgc2Vuc2l0aXZpdHkgPSAwLjA4ZjsKCQkJCQkJZGFtcGVuZWRfYWNjW2ldICs9IChhY2NlbGVyb21ldGVyW2ldIC0gb2xkX2FjY1tpXSkgKiBzZW5zaXRpdml0eTsKCQkJCQkJLy9FdmVuIG91dCBkcmlmdCBvdmVyIHRpbWUKCQkJCQkJZGFtcGVuZWRfYWNjW2ldICo9IDAuOTk7CgkJCQkJfQoJCQkJfQoJCQl9CgkJCQlicmVhazsKCQkJY2FzZSAoU2Vuc29yLlRZUEVfTUFHTkVUSUNfRklFTEQpOiB7CgkJCQluZWVkc1JlY2FsYyA9IHRydWU7CgkJCQlTeXN0ZW0uYXJyYXljb3B5KHZhbHMsIDAsIG1hZ25ldGljX2ZpZWxkLCAwLCAzKTsKCQkJfQoJCQkJYnJlYWs7CgkJfQoJfQoKCUBPdmVycmlkZQoJcHVibGljIHZvaWQgb25BY2N1cmFjeUNoYW5nZWQoU2Vuc29yIGV2ZW50LCBpbnQgcmVzKSB7Cgl9CgoJLy8gVGhlIGNvbnN0cnVjdG9yIHdpbGwgdXNlIGEgY29udGV4dCBvYmplY3QgdG8gcmVnaXN0ZXIgaXRzZWxmIGZvciB2YXJpb3VzIGlucHV0czoKCXB1YmxpYyBUaWx0U2Vuc29yKENvbnRleHQgYykgewoJCW1hbiA9IChTZW5zb3JNYW5hZ2VyKSBjLmdldFN5c3RlbVNlcnZpY2UoQ29udGV4dC5TRU5TT1JfU0VSVklDRSk7CgkJbWFnX3NlbnNvciA9IG1hbi5nZXREZWZhdWx0U2Vuc29yKFNlbnNvci5UWVBFX01BR05FVElDX0ZJRUxEKTsKCQlhY2Nfc2Vuc29yID0gbWFuLmdldERlZmF1bHRTZW5zb3IoU2Vuc29yLlRZUEVfQUNDRUxFUk9NRVRFUik7CgkJLy9TZW5zb3IgZ3lyX3NlbnNvciA9IG1hbi5nZXREZWZhdWx0U2Vuc29yKFNlbnNvci5UWVBFX0dZUk9TQ09QRSk7CgkJcmVzdW1lKCk7CgkJaWYgKGhhc19hY2MpIHsKCQkJdGlsdEF2YWlsYmxlID0gdHJ1ZTsKCQkJaWYgKGhhc19tYWcpIHsKCQkJCUxvZy5kKCJUaWx0Q2FsYyIsICJVc2luZyBhY2NlbGVyb21ldGVyICsgY29tcGFzcy4iKTsKCQkJfQoJCQllbHNlIHsKCQkJCUxvZy5kKCJUaWx0Q2FsYyIsICJVc2luZyBvbmx5IGFjY2VsZXJvbWV0ZXIuIik7CgkJCX0KCQl9CgkJZWxzZSB7CgkJCXRpbHRBdmFpbGJsZSA9IGZhbHNlOwoJCQlMb2cuZCgiVGlsdENhbGMiLCAiTm8gYWNjZXB0YWJsZSBoYXJkd2FyZSBmb3VuZCwgdGlsdCBub3QgYXZhaWxhYmxlLiIpOwoJCQkvL05vIHVzZSBpbiBoYXZpbmcgbGlzdGVuZXJzIHJlZ2lzdGVyZWQKCQkJcGF1c2UoKTsKCQl9Cgl9CgoJQE92ZXJyaWRlCglwcm90ZWN0ZWQgdm9pZCBmaW5hbGl6ZSgpIHRocm93cyBUaHJvd2FibGUgewoJCXBhdXNlKCk7CgkJc3VwZXIuZmluYWxpemUoKTsKCX0KCglwdWJsaWMgYm9vbGVhbiBpc1RpbHRBYmFpbGFibGUoKSB7CgkJcmV0dXJuIHRpbHRBdmFpbGJsZTsKCX0KCgkvLyBXaWxsIHJldHVybiB0aGUgbW9zdCB1cC10by1kYXRlIHRpbHQgZGF0YSBpbiB0aGUgdmFsc1tdIGFycmF5CglwdWJsaWMgdm9pZCBnZXRUaWx0KGZsb2F0W10gdmFscykgewoJCS8vIElmIHNvbWUgb2YgdGhlIGRhdGEgaGFzIGJlZW4gY2hhbmdlZCwgdGhlbiB3ZSBuZWVkIHRvIHJlY2FsY3VsYXRlIHNvbWUgdGhpbmdzLi4uCgkJaWYgKG5lZWRzUmVjYWxjKSB7CgkJCWlmIChoYXNfYWNjKSB7CgkJCQlpZiAoaGFzX21hZykgewoJCQkJCWZsb2F0W10gUiA9IHsgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCB9OwoJCQkJCS8vIENhbGN1bGF0ZSB0aGUgcm90YXRpb24gbWF0cml4LCBhbmQgdXNlIHRoYXQgdG8gZ2V0IHRoZSBvcmllbnRhdGlvbjoKCQkJCQlpZiAoU2Vuc29yTWFuYWdlci5nZXRSb3RhdGlvbk1hdHJpeChSLCBudWxsLCBhY2NlbGVyb21ldGVyLCBtYWduZXRpY19maWVsZCkpIHsKCQkJCQkJU2Vuc29yTWFuYWdlci5nZXRPcmllbnRhdGlvbihSLCB0aWx0X2RhdGEpOwoJCQkJCX0KCQkJCX0KCQkJCS8vQ2hlYXQgYnkgYXNzdW1pbmcgdXNlciB3aWxsIGJlIGhvbGRpbmcgZGV2aWNlIGluIGEgY2VydGFpbiB3YXkuIAoJCQkJZWxzZSB7CgkJCQkJdGlsdF9kYXRhWzFdID0gZGFtcGVuZWRfYWNjWzBdOwoJCQkJfQoJCQl9CgkJCW5lZWRzUmVjYWxjID0gZmFsc2U7CgkJfQoJCVN5c3RlbS5hcnJheWNvcHkodGlsdF9kYXRhLCAwLCB2YWxzLCAwLCAzKTsKCX0KCn0K