Android: Shake Detector too Sensitive

Erez picture Erez · Feb 14, 2013 · Viewed 8.4k times · Source

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];
        }
      }
}

Answer

AMD picture AMD · Mar 6, 2013

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);
        }
    };