2013-02-14 9 views
13

Sto provando a rilevare una scossa - e sto usando il seguente codice, funziona molto bene, ma in alcuni dispositivi (Galaxy note 2 per esempio) rileva troppo presto lo scuotimento (in alcuni casi - quando ho appena tenere il telefono ancora)Android: Rilevatore scuotimento troppo sensibile

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

Che dire scalare facendo multiplaying di un delta? –

+0

Prova questo. http://stackoverflow.com/questions/2317428/android-i-want-to-shake-it –

+0

se hai eseguito il controllo della sensibilità in modo da spiegare chi modifica il valore per il controllo della sensibilità –

risposta

7

Verificare accelerazione con più alto numero di scossa. Dai un'occhiata a questo codice funziona per 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); 
     } 
    }; 
+0

se si dispone del controllo della sensibilità, quindi spiegare chi cambia valore per il controllo della sensibilità –

+0

Ciò rileverà qualsiasi movimento SINGLE improvviso che potrebbe non essere scosso: basta far cadere il telefono per attivarlo. – CloudWalker

0

Start dalla sensibilità più bassa, ma a poco a poco ad aumentare se sha re sopra qualche soglia iniziale continua per un tempo più lungo. Questo è simile alla percezione umana.

+0

Il problema è che funziona bene in altri telefoni. .. – Erez

0

Prova questo ... e fammi sapere ..

public class ShakeListener implements SensorEventListener { 
    private String TAG = ShakeListener.class.getSimpleName(); 
    private static final int FORCE_THRESHOLD = 800; 
    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) { 

     Log.d(TAG,"ShakeListener invoked---->"); 
     mContext = context; 
     resume(); 
    } 

    public void setOnShakeListener(OnShakeListener listener) { 
     Log.d(TAG,"ShakeListener setOnShakeListener invoked---->"); 
     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[SensorManager.DATA_X] 
        + event.values[SensorManager.DATA_Y] 
        + event.values[SensorManager.DATA_Z] - mLastX - mLastY 
        - mLastZ) 
        /diff * 10000; 
      if (speed > FORCE_THRESHOLD) { 
       if ((++mShakeCount >= SHAKE_COUNT) 
         && (now - mLastShake > SHAKE_DURATION)) { 
        mLastShake = now; 
        mShakeCount = 0; 
        Log.d(TAG,"ShakeListener mShakeListener---->"+mShakeListener); 
        if (mShakeListener != null) { 
         mShakeListener.onShake(); 
        } 
       } 
       mLastForce = now; 
      } 
      mLastTime = now; 
      mLastX = event.values[SensorManager.DATA_X]; 
      mLastY = event.values[SensorManager.DATA_Y]; 
      mLastZ = event.values[SensorManager.DATA_Z]; 
     } 
    } 
} 
0

Questo funziona bene con me:

public class ShakeEventListener implements SensorEventListener { 
public final static int SHAKE_LIMIT = 15; 
public final static int LITTLE_SHAKE_LIMIT = 5; 

private SensorManager mSensorManager; 
private float mAccel = 0.00f; 
private float mAccelCurrent = SensorManager.GRAVITY_EARTH; 
private float mAccelLast = SensorManager.GRAVITY_EARTH; 

private ShakeListener listener; 

public interface ShakeListener { 
    public void onShake(); 
    public void onLittleShake(); 
} 

public ShakeEventListener(ShakeListener l) { 
    Activity a = (Activity) l; 
    mSensorManager = (SensorManager) a.getSystemService(Context.SENSOR_SERVICE); 
    listener = l; 
    registerListener(); 
} 

public ShakeEventListener(Activity a, ShakeListener l) { 
    mSensorManager = (SensorManager) a.getSystemService(Context.SENSOR_SERVICE); 
    listener = l; 
    registerListener(); 
} 

public void registerListener() { 
    mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); 
} 

public void unregisterListener() { 
    mSensorManager.unregisterListener(this); 
} 

public void onSensorChanged(SensorEvent se) { 
    float x = se.values[0]; 
    float y = se.values[1]; 
    float z = se.values[2]; 
    mAccelLast = mAccelCurrent; 
    mAccelCurrent = (float) FloatMath.sqrt(x*x + y*y + z*z); 
    float delta = mAccelCurrent - mAccelLast; 
    mAccel = mAccel * 0.9f + delta; 
    if(mAccel > SHAKE_LIMIT) 
     listener.onShake(); 
    else if(mAccel > LITTLE_SHAKE_LIMIT) 
     listener.onLittleShake(); 
} 

public void onAccuracyChanged(Sensor sensor, int accuracy) {} 
} 

Reference