131 votes

Comment détecter les secousses avec Android ?

Comment détecter une secousse avec Android ? Comment détecter la direction de la secousse ?

Je souhaite modifier l'image d'une vue d'image lorsqu'une secousse se produit.

33 votes

J'ai fait une recherche sur Google et j'ai trouvé cette question en tête de liste...

0 votes

stackoverflow.com/a/54745560/4307338 vous pouvez consulter cette réponse

186voto

N-JOY Points 5695

Du point de vue du code, vous devez implémenter le SensorListener :

public class ShakeActivity extends Activity implements SensorListener

Vous devez acquérir un SensorManager :

sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

Et enregistrer ce capteur avec les drapeaux souhaités :

sensorMgr.registerListener(this,
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_GAME);

Dans votre méthode onSensorChange(), vous déterminez s'il s'agit d'une secousse ou non :

public void onSensorChanged(int sensor, float[] values) {
  if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
    long curTime = System.currentTimeMillis();
    // only allow one update every 100ms.
    if ((curTime - lastUpdate) > 100) {
      long diffTime = (curTime - lastUpdate);
      lastUpdate = curTime;

      x = values[SensorManager.DATA_X];
      y = values[SensorManager.DATA_Y];
      z = values[SensorManager.DATA_Z];

      float speed = Math.abs(x+y+z - last_x - last_y - last_z) / diffTime * 10000;

      if (speed > SHAKE_THRESHOLD) {
        Log.d("sensor", "shake detected w/ speed: " + speed);
        Toast.makeText(this, "shake detected w/ speed: " + speed, Toast.LENGTH_SHORT).show();
      }
      last_x = x;
      last_y = y;
      last_z = z;
    }
  }
}

Le seuil de secousse est défini comme suit :

private static final int SHAKE_THRESHOLD = 800;

Il existe également d'autres méthodes pour détecter les mouvements de tremblement. lien. (Si ce lien ne fonctionne pas ou s'il est mort, voir cette archive web .).

Jetez un coup d'œil à ceci exemple pour Android shake detect listener.

Remarque : SensorListener est obsolète. nous pouvons utiliser SensorEventListener au lieu de cela. Voici un exemple rapide utilisant SensorEventListener.

Merci.

17 votes

Ne pas utiliser la classe SensorListener, car elle est dépréciée, mais SensorEventListener.

1 votes

Le lien est mort... Voici l'article sur archive.org : web.archive.org/web/20100324212856/http://www.codeshogun.com/

0 votes

Je trouve que la sensibilité change en fonction de l'appareil. ce qui semblait être une détection de secousses parfaitement acceptable sur le galaxy nexus doit être une secousse beaucoup plus violente sur un galaxy III exécutant la même application. si je la rends moins sensible pour cet appareil, elle sera trop sensible sur quelque chose comme le nexus. hmmmmmmm.

66voto

MarvinLabs Points 13401

Google est d'une grande aide .

/* The following code was written by Matthew Wiggins
 * and is released under the APACHE 2.0 license
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 */
package com.hlidskialf.android.hardware;

import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.content.Context;
import java.lang.UnsupportedOperationException;

public class ShakeListener implements SensorListener 
{
  private static final int FORCE_THRESHOLD = 350;
  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 = 3;

  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 = mSensorMgr.registerListener(this, SensorManager.SENSOR_ACCELEROMETER, SensorManager.SENSOR_DELAY_GAME);
    if (!supported) {
      mSensorMgr.unregisterListener(this, SensorManager.SENSOR_ACCELEROMETER);
      throw new UnsupportedOperationException("Accelerometer not supported");
    }
  }

  public void pause() {
    if (mSensorMgr != null) {
      mSensorMgr.unregisterListener(this, SensorManager.SENSOR_ACCELEROMETER);
      mSensorMgr = null;
    }
  }

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

  public void onSensorChanged(int sensor, float[] values) 
  {
    if (sensor != SensorManager.SENSOR_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(values[SensorManager.DATA_X] + values[SensorManager.DATA_Y] + 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;
          if (mShakeListener != null) { 
            mShakeListener.onShake(); 
          }
        }
        mLastForce = now;
      }
      mLastTime = now;
      mLastX = values[SensorManager.DATA_X];
      mLastY = values[SensorManager.DATA_Y];
      mLastZ = values[SensorManager.DATA_Z];
    }
  }

}

3 votes

java.lang.SecurityException: Requires VIBRATE permission

2 votes

SensorManager.DATA_[X,Y,Z] sont désormais obsolètes.

0 votes

@RanyAlbegWein êtes-vous sûr ? J'ai vérifié la documentation et l'IDE et il n'y a pas eu de biffure ou d'avertissement de dépréciation.

53voto

Borys Points 488

Vous pouvez également consulter la bibliothèque Sismique

public class Demo extends Activity implements ShakeDetector.Listener {
  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    ShakeDetector sd = new ShakeDetector(this);

    // A non-zero delay is required for Android 12 and up (https://github.com/square/seismic/issues/24)
    int sensorDelay = SensorManager.SENSOR_DELAY_GAME

    sd.start(sensorManager, sensorDelay);

    TextView tv = new TextView(this);
    tv.setGravity(CENTER);
    tv.setText("Shake me, bro!");
    setContentView(tv, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
  }

  @Override public void hearShake() {
    Toast.makeText(this, "Don't shake me, bro!", Toast.LENGTH_SHORT).show();
  }
}

3 votes

Réponse sous-estimée.

1 votes

Celui-ci est meilleur. Cette bibliothèque est développée par Square.

0 votes

20voto

Tad Points 98

Il y a déjà beaucoup de solutions à cette question, mais je voulais en poster une :

  • N'utilise pas de bibliothèque supprimée dans l'API 3
  • Calcule correctement l'amplitude de l'accélération
  • Application correcte d'un délai d'attente entre les événements de secousses

Voici une telle solution :

// variables for shake detection
private static final float SHAKE_THRESHOLD = 3.25f; // m/S**2
private static final int MIN_TIME_BETWEEN_SHAKES_MILLISECS = 1000;
private long mLastShakeTime;
private SensorManager mSensorMgr;

Pour initialiser la minuterie :

// Get a sensor manager to listen for shakes
mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

// Listen for shakes
Sensor accelerometer = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometer != null) {
    mSensorMgr.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}

SensorEventListener à remplacer :

@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        long curTime = System.currentTimeMillis();
        if ((curTime - mLastShakeTime) > MIN_TIME_BETWEEN_SHAKES_MILLISECS) {

            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];

            double acceleration = Math.sqrt(Math.pow(x, 2) +
                    Math.pow(y, 2) +
                    Math.pow(z, 2)) - SensorManager.GRAVITY_EARTH;
            Log.d(APP_NAME, "Acceleration is " + acceleration + "m/s^2");

            if (acceleration > SHAKE_THRESHOLD) {
                mLastShakeTime = curTime;
                Log.d(APP_NAME, "Shake, Rattle, and Roll");
            }
        }
    }
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // Ignore
}

Lorsque vous avez terminé

// Stop listening for shakes
mSensorMgr.unregisterListener(this);

10voto

Morteza Soleimani Points 1663

Depuis SensorListener est obsolète utilisez donc le code suivant :

/* put this into your activity class */
private SensorManager mSensorManager;
private float mAccel; // acceleration apart from gravity
private float mAccelCurrent; // current acceleration including gravity
private float mAccelLast; // last acceleration including gravity

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
  }

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

@Override
protected void onResume() {
  super.onResume();
  mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
protected void onPause() {
  mSensorManager.unregisterListener(mSensorListener);
  super.onPause();
}

Ensuite :

/* do this in onCreate */
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;

La question avec tous les détails peut être trouvée ici :

Android : Je veux le secouer

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X