How to detect movement of an android device?
Definitely work with the accelerometer:
// Start with some variablesprivate SensorManager sensorMan;private Sensor accelerometer;private float[] mGravity;private float mAccel;private float mAccelCurrent;private float mAccelLast;// In onCreate methodsensorMan = (SensorManager)getSystemService(SENSOR_SERVICE);accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);mAccel = 0.00f;mAccelCurrent = SensorManager.GRAVITY_EARTH;mAccelLast = SensorManager.GRAVITY_EARTH;// And these:@Overridepublic void onResume() { super.onResume(); sensorMan.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);}@Overrideprotected void onPause() { super.onPause(); sensorMan.unregisterListener(this);}@Overridepublic void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){ mGravity = event.values.clone(); // Shake detection float x = mGravity[0]; float y = mGravity[1]; float z = mGravity[2]; mAccelLast = mAccelCurrent; mAccelCurrent = FloatMath.sqrt(x*x + y*y + z*z); float delta = mAccelCurrent - mAccelLast; mAccel = mAccel * 0.9f + delta; // Make this higher or lower according to how much // motion you want to detect if(mAccel > 3){ // do something } }}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) { // required method}
I used the following class:
public class MovementDetector implements SensorEventListener {protected final String TAG = getClass().getSimpleName();private SensorManager sensorMan;private Sensor accelerometer;private MovementDetector() {}private static MovementDetector mInstance;public static MovementDetector getInstance() { if (mInstance == null) { mInstance = new MovementDetector(); mInstance.init(); } return mInstance;}//////////////////////private HashSet<Listener> mListeners = new HashSet<MovementDetector.Listener>();private void init() { sensorMan = (SensorManager) GlobalData.getInstance().getContext().getSystemService(Context.SENSOR_SERVICE); accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);}public void start() { sensorMan.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);}public void stop() { sensorMan.unregisterListener(this);}public void addListener(Listener listener) { mListeners.add(listener);}/* (non-Javadoc) * @see android.hardware.SensorEventListener#onSensorChanged(android.hardware.SensorEvent) */@Overridepublic void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) { float x = event.values[0]; float y = event.values[1]; float z = event.values[2]; float diff = (float) Math.sqrt(x * x + y * y + z * z); if (diff > 0.5) // 0.5 is a threshold, you can test it and change it Log.d(TAG,"Device motion detected!!!!"); for (Listener listener : mListeners) { listener.onMotionDetected(event, diff); } }}/* (non-Javadoc) * @see android.hardware.SensorEventListener#onAccuracyChanged(android.hardware.Sensor, int) */@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub}public interface Listener { void onMotionDetected(SensorEvent event, float acceleration); }}
Usage:
On my activity onCrate()
:
MovementDetector.getInstance().addListener(new MovementDetector.Listener() { @Override public void onMotionDetected(SensorEvent event, float acceleration) { mMotionDetectionTextView.setText("Acceleration: ["+String.format("%.3f",event.values[0])+","+String.format("%.3f",event.values[1])+","+String.format("%.3f",event.values[2])+"] "+String.format("%.3f", acceleration)); if (acceleration > SettingsHelper.getInstance().getMotionDetectionThreshold()){ mMotionDetectionTextView.setTextColor(Color.RED); } else { mMotionDetectionTextView.setTextColor(Color.WHITE); } } });
On my activity onResume()
:
MovementDetector.getInstance().start();
On my activity onPause()
:
MovementDetector.getInstance().stop();
This code is for walking detection (Modified from @anthropomo code)
to get smoother value.
// initialize
private SensorManager sensorMan;private Sensor accelerometer;private float[] mGravity;private double mAccel;private double mAccelCurrent;private double mAccelLast;private boolean sensorRegistered = false;
// onCreate
sensorMan = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mAccel = 0.00f; mAccelCurrent = SensorManager.GRAVITY_EARTH; mAccelLast = SensorManager.GRAVITY_EARTH; sensorMan.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL); sensorRegistered = true;
// onSensorChanged
private int hitCount = 0;private double hitSum = 0;private double hitResult = 0;private final int SAMPLE_SIZE = 50; // change this sample size as you want, higher is more precise but slow measure.private final double THRESHOLD = 0.2; // change this threshold as you want, higher is more spike movement@Overridepublic void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { mGravity = event.values.clone(); // Shake detection double x = mGravity[0]; double y = mGravity[1]; double z = mGravity[2]; mAccelLast = mAccelCurrent; mAccelCurrent = Math.sqrt(x * x + y * y + z * z); double delta = mAccelCurrent - mAccelLast; mAccel = mAccel * 0.9f + delta; if (hitCount <= SAMPLE_SIZE) { hitCount++; hitSum += Math.abs(mAccel); } else { hitResult = hitSum / SAMPLE_SIZE; Log.d(TAG, String.valueOf(hitResult)); if (hitResult > THRESHOLD) { Log.d(TAG, "Walking"); } else { Log.d(TAG, "Stop Walking"); } hitCount = 0; hitSum = 0; hitResult = 0; } }}