I'm trying to detect a shake - and i'm using the following code, it works very good, but in some devices (Galaxy note 2 for example) it detects the shake too soon (in some cases - when i just hold the phone still)
main.java:
ShakeListener mShaker = new ShakeListener(this);
mShaker.setOnShakeListener(new ShakeListener.OnShakeListener () {
public void onShake()
{
// Some code...
}
});
}
ShakeListener.java :
package com.my.app;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.widget.Toast;
import android.content.Context;
import java.lang.UnsupportedOperationException;
public class ShakeListener implements SensorEventListener
{
private static final int FORCE_THRESHOLD = 700;
private static final int TIME_THRESHOLD = 100;
private static final int SHAKE_TIMEOUT = 500;
private static final int SHAKE_DURATION = 1000;
private static final int SHAKE_COUNT = 5;
private SensorManager mSensorMgr;
private float mLastX=-1.0f, mLastY=-1.0f, mLastZ=-1.0f;
private long mLastTime;
private OnShakeListener mShakeListener;
private Context mContext;
private int mShakeCount = 0;
private long mLastShake;
private long mLastForce;
public interface OnShakeListener
{
public void onShake();
}
public ShakeListener(Context context)
{
mContext = context;
resume();
}
public void setOnShakeListener(OnShakeListener listener)
{
mShakeListener = listener;
}
public void resume() {
mSensorMgr = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
if (mSensorMgr == null) {
throw new UnsupportedOperationException("Sensors not supported");
}
boolean supported = false;
try {
supported = mSensorMgr.registerListener(this, mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
} catch (Exception e) {Toast.makeText(mContext, "Shaking not supported", Toast.LENGTH_LONG).show();}
if ((!supported)&&(mSensorMgr != null)) mSensorMgr.unregisterListener(this);
}
public void pause() {
if (mSensorMgr != null) {
mSensorMgr.unregisterListener(this);
mSensorMgr = null;
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
public void onSensorChanged(SensorEvent event)
{
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
long now = System.currentTimeMillis();
if ((now - mLastForce) > SHAKE_TIMEOUT) {
mShakeCount = 0;
}
if ((now - mLastTime) > TIME_THRESHOLD) {
long diff = now - mLastTime;
float speed = Math.abs(event.values[0] + event.values[1] + event.values[2] - mLastX - mLastY - mLastZ) / diff * 10000;
if (speed > FORCE_THRESHOLD) {
if ((++mShakeCount >= SHAKE_COUNT) && (now - mLastShake > SHAKE_DURATION)) {
mLastShake = now;
mShakeCount = 0;
if (mShakeListener != null) {
mShakeListener.onShake();
}
}
mLastForce = now;
}
mLastTime = now;
mLastX = event.values[0];
mLastY = event.values[1];
mLastZ = event.values[2];
}
}
}
Check Acceleration with higher number of shake. Take a Look on this code it works for me.
private final SensorEventListener mSensorListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent se) {
float x = se.values[0];
float y = se.values[1];
float z = se.values[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) Math.sqrt((double) (x * x + y * y + z * z));
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta; // perform low-cut filter
if (mAccel > 8) {
Toast.makeText(getApplicationContext(),
"You have shaken your phone", Toast.LENGTH_SHORT).show();
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.i("Sensor", "mAccel" + mAccel);
}
};