Come aggiornare l'app dopo aver scosso il dispositivo?


254

Devo aggiungere una funzione di scuotimento che aggiornerà la mia applicazione Android.

Tutto ciò che trovo della documentazione implica l'implementazione di SensorListener, ma Eclipse mi dice che è deprecato e suggerito SensorEventListener.

Qualcuno che ha una bella guida su come faccio a creare questo shake controller?


Trovato un esempio che alla fine ha funzionato: android.hlidskialf.com/blog/code/…
Sara

Poiché la soluzione all'URL fornita da Sara utilizza una classe obsoleta, l'ho leggermente modificata qui per farlo funzionare
Sigwann

17
Questo è vecchio ma l'ho appena trovato e ha dovuto fare +1 per il titolo
codeMagic

Risposte:


317

Ecco un esempio di codice. Metti questo nella tua classe di attività:

  /* 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();
  }

E aggiungi questo al tuo metodo onCreate:

    /* 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;

Puoi quindi chiedere "mAccel" dove vuoi nella tua applicazione per l'accelerazione corrente, indipendente dall'asse e pulita dall'accelerazione statica come la gravità. Sarà di ca. 0 se non c'è movimento e, diciamo> 2 se il dispositivo è scosso.

Sulla base dei commenti - per testare questo:

if (mAccel > 12) {
    Toast toast = Toast.makeText(getApplicationContext(), "Device has shaken.", Toast.LENGTH_LONG);
    toast.show();
}

Appunti:

L'accelometro deve essere disattivato su Pausa e attivato su Riprendi per risparmiare risorse (CPU, batteria). Il codice presuppone che siamo sul pianeta Terra ;-) e inizializza l'accelerazione alla gravità terrestre. Altrimenti si otterrebbe un forte "tremolio" quando l'applicazione si avvia e "colpisce" il terreno dalla caduta libera. Tuttavia, il codice si abitua alla gravitazione a causa del filtro low-cut e funzionerebbe anche su altri pianeti o nello spazio libero, una volta inizializzato. (non sai mai per quanto tempo rimarrà in uso la tua applicazione ... ;-)


10
Questa riga di codice mAccel = mAccel * 0.9f + delta; // perform low-cut filterdovrebbe essere mAccel = mAccel * 0.9f + delta * 0.1f; // perform low-cut filter?
Randy Sugianto 'Yuku'

3
Ben fatto! Ho anche aggiunto un segno di spunta per evitare le scosse troppo spesso (nella mia app l'ho impostato su 750 ms dopo l'ultima scossa) ... I Calendar last = Calendar.getInstance(); Calendar now = Calendar.getInstance(); last.setTime(last_date); now.setTime(new Date()); long diff = now.getTimeInMillis() - last.getTimeInMillis(); if(diff >= 750) { ... } nomi dei metodi dovrebbero essere corretti (non ho il codice con me ... )
TesX

9
Il compilatore suggerisce di usare: android.util.FloatMath.sqrt(x*x + y*y + z*z);invece di evitare una conversione
Casebash,

3
Per verificare ciò, utilizzare quanto segue: if (mAccel> 12) {Toast toast = Toast.makeText (getApplicationContext (), "Il dispositivo è stato scosso.", Toast.LENGTH_LONG); toast.show (); }

1
Dove posso controllare il valore di mAccel? Nel mio onCreate o all'interno di OnSernsorChanged?
Vanquiza,

128

Ecco il mio codice per il rilevamento dei gesti con vibrazione:

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;


/**
 * Listener that detects shake gesture.
 */
public class ShakeEventListener implements SensorEventListener {


  /** Minimum movement force to consider. */
  private static final int MIN_FORCE = 10;

  /**
   * Minimum times in a shake gesture that the direction of movement needs to
   * change.
   */
  private static final int MIN_DIRECTION_CHANGE = 3;

  /** Maximum pause between movements. */
  private static final int MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE = 200;

  /** Maximum allowed time for shake gesture. */
  private static final int MAX_TOTAL_DURATION_OF_SHAKE = 400;

  /** Time when the gesture started. */
  private long mFirstDirectionChangeTime = 0;

  /** Time when the last movement started. */
  private long mLastDirectionChangeTime;

  /** How many movements are considered so far. */
  private int mDirectionChangeCount = 0;

  /** The last x position. */
  private float lastX = 0;

  /** The last y position. */
  private float lastY = 0;

  /** The last z position. */
  private float lastZ = 0;

  /** OnShakeListener that is called when shake is detected. */
  private OnShakeListener mShakeListener;

  /**
   * Interface for shake gesture.
   */
  public interface OnShakeListener {

    /**
     * Called when shake gesture is detected.
     */
    void onShake();
  }

  public void setOnShakeListener(OnShakeListener listener) {
    mShakeListener = listener;
  }

  @Override
  public void onSensorChanged(SensorEvent se) {
    // get sensor data
    float x = se.values[SensorManager.DATA_X];
    float y = se.values[SensorManager.DATA_Y];
    float z = se.values[SensorManager.DATA_Z];

    // calculate movement
    float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);

    if (totalMovement > MIN_FORCE) {

      // get time
      long now = System.currentTimeMillis();

      // store first movement time
      if (mFirstDirectionChangeTime == 0) {
        mFirstDirectionChangeTime = now;
        mLastDirectionChangeTime = now;
      }

      // check if the last movement was not long ago
      long lastChangeWasAgo = now - mLastDirectionChangeTime;
      if (lastChangeWasAgo < MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE) {

        // store movement data
        mLastDirectionChangeTime = now;
        mDirectionChangeCount++;

        // store last sensor data 
        lastX = x;
        lastY = y;
        lastZ = z;

        // check how many movements are so far
        if (mDirectionChangeCount >= MIN_DIRECTION_CHANGE) {

          // check total duration
          long totalDuration = now - mFirstDirectionChangeTime;
          if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE) {
            mShakeListener.onShake();
            resetShakeParameters();
          }
        }

      } else {
        resetShakeParameters();
      }
    }
  }

  /**
   * Resets the shake parameters to their default values.
   */
  private void resetShakeParameters() {
    mFirstDirectionChangeTime = 0;
    mDirectionChangeCount = 0;
    mLastDirectionChangeTime = 0;
    lastX = 0;
    lastY = 0;
    lastZ = 0;
  }

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

}

Aggiungi questo nella tua attività:

  private SensorManager mSensorManager;

  private ShakeEventListener mSensorListener;

...

in onCreate () aggiungi:

    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mSensorListener = new ShakeEventListener();   

    mSensorListener.setOnShakeListener(new ShakeEventListener.OnShakeListener() {

      public void onShake() {
        Toast.makeText(KPBActivityImpl.this, "Shake!", Toast.LENGTH_SHORT).show();
      }
    });

e:

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

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

2
Perché registri l'ascoltatore due volte, una volta in onCreate e di nuovo in onResume? onCreate non viene mai chiamato senza onResume, quindi è possibile rimuovere la chiamata del registro in onCreate.
Matthias,

1
Inoltre, se sei registrato su onResume, probabilmente vorrai annullare la registrazione su onPause, non su Stop. A parte questo, grandi cose, molto apprezzate.
Matthias,

1
Il listener deve essere non registrato in onPause (), non onStop (). Se lasci il telefono su questa attività "consumerà" tutta la batteria.
lomza,

2
@lomza probabilmente hai ragione, dovrebbe essere non registrato suPause (), ora cambiato.
Peceps,

1
Non dimenticare mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);in onCreate (). Altrimenti, funziona meravigliosamente! Grazie!
BVB

33

Ecco un'altra implementazione che si basa su alcuni dei suggerimenti qui presenti e sul codice dal sito degli sviluppatori Android.

MainActivity.java

public class MainActivity extends Activity {

    private ShakeDetector mShakeDetector;
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ShakeDetector initialization
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mShakeDetector = new ShakeDetector(new OnShakeListener() {
            @Override
            public void onShake() {
                // Do stuff!
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
    }

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

ShakeDetector.java

package com.example.test;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;

public class ShakeDetector implements SensorEventListener {

    // Minimum acceleration needed to count as a shake movement
    private static final int MIN_SHAKE_ACCELERATION = 5;

    // Minimum number of movements to register a shake
    private static final int MIN_MOVEMENTS = 2;

    // Maximum time (in milliseconds) for the whole shake to occur
    private static final int MAX_SHAKE_DURATION = 500;

    // Arrays to store gravity and linear acceleration values
    private float[] mGravity = { 0.0f, 0.0f, 0.0f };
    private float[] mLinearAcceleration = { 0.0f, 0.0f, 0.0f };

    // Indexes for x, y, and z values
    private static final int X = 0;
    private static final int Y = 1;
    private static final int Z = 2;

    // OnShakeListener that will be notified when the shake is detected
    private OnShakeListener mShakeListener;

    // Start time for the shake detection
    long startTime = 0;

    // Counter for shake movements
    int moveCount = 0;

    // Constructor that sets the shake listener
    public ShakeDetector(OnShakeListener shakeListener) {
        mShakeListener = shakeListener;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // This method will be called when the accelerometer detects a change.

        // Call a helper method that wraps code from the Android developer site
        setCurrentAcceleration(event);

        // Get the max linear acceleration in any direction
        float maxLinearAcceleration = getMaxCurrentLinearAcceleration();

        // Check if the acceleration is greater than our minimum threshold
        if (maxLinearAcceleration > MIN_SHAKE_ACCELERATION) {
            long now = System.currentTimeMillis();

            // Set the startTime if it was reset to zero
            if (startTime == 0) {
                startTime = now;
            }

            long elapsedTime = now - startTime;

            // Check if we're still in the shake window we defined
            if (elapsedTime > MAX_SHAKE_DURATION) {
                // Too much time has passed. Start over!
                resetShakeDetection();
            }
            else {
                // Keep track of all the movements
                moveCount++;

                // Check if enough movements have been made to qualify as a shake
                if (moveCount > MIN_MOVEMENTS) {
                    // It's a shake! Notify the listener.
                    mShakeListener.onShake();

                    // Reset for the next one!
                    resetShakeDetection();
                }
            }
        }
    }

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

    private void setCurrentAcceleration(SensorEvent event) {
        /*
         *  BEGIN SECTION from Android developer site. This code accounts for 
         *  gravity using a high-pass filter
         */

        // alpha is calculated as t / (t + dT)
        // with t, the low-pass filter's time-constant
        // and dT, the event delivery rate

        final float alpha = 0.8f;

        // Gravity components of x, y, and z acceleration
        mGravity[X] = alpha * mGravity[X] + (1 - alpha) * event.values[X];
        mGravity[Y] = alpha * mGravity[Y] + (1 - alpha) * event.values[Y];
        mGravity[Z] = alpha * mGravity[Z] + (1 - alpha) * event.values[Z];

        // Linear acceleration along the x, y, and z axes (gravity effects removed)
        mLinearAcceleration[X] = event.values[X] - mGravity[X];
        mLinearAcceleration[Y] = event.values[Y] - mGravity[Y];
        mLinearAcceleration[Z] = event.values[Z] - mGravity[Z];

        /*
         *  END SECTION from Android developer site
         */
    }

    private float getMaxCurrentLinearAcceleration() {
        // Start by setting the value to the x value
        float maxLinearAcceleration = mLinearAcceleration[X];

        // Check if the y value is greater
        if (mLinearAcceleration[Y] > maxLinearAcceleration) {
            maxLinearAcceleration = mLinearAcceleration[Y];
        }

        // Check if the z value is greater
        if (mLinearAcceleration[Z] > maxLinearAcceleration) {
            maxLinearAcceleration = mLinearAcceleration[Z];
        }

        // Return the greatest value
        return maxLinearAcceleration;
    }

    private void resetShakeDetection() {
        startTime = 0;
        moveCount = 0;
    }

    // (I'd normally put this definition in it's own .java file)
    public interface OnShakeListener {
        public void onShake();
    }
}

Ciao! come posso impostare call after shake hai avuto qualche esempio di lavoro per questo?
Muhammad Usman Ghani

Non sono sicuro di cosa intendi per "after shake". Il metodo onShake () viene chiamato quando viene rilevata la vibrazione. Vuoi aspettare fino a quando l'agitazione è finita? In tal caso, dovresti aggiungere un flag o qualcosa all'interno di onSensorChanged () e cambiare come e quando viene chiamato resetShakeDetection ().
Ben Jakuben,

@BenJakuben Come posso verificare questo modello di agitazione? Come posso archiviare nel database SQLite per scopi di verifica futuri?
sam_k,

Come posso ottenere un conteggio delle vibrazioni nella DoShake()funzione?
Si8

9

Mi è piaciuta molto la risposta di Peterdk. Mi sono preso la responsabilità di fare un paio di modifiche al suo codice.

file: ShakeDetector.java

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;

public class ShakeDetector implements SensorEventListener {

    // The gForce that is necessary to register as shake. Must be greater than 1G (one earth gravity unit)
    private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
    private static final int SHAKE_SLOP_TIME_MS = 500;
    private static final int SHAKE_COUNT_RESET_TIME_MS = 3000;

    private OnShakeListener mListener;
    private long mShakeTimestamp;
    private int mShakeCount;

    public void setOnShakeListener(OnShakeListener listener) {
        this.mListener = listener;
    }

    public interface OnShakeListener {
        public void onShake(int count);
    }

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

    @Override
    public void onSensorChanged(SensorEvent event) {

        if (mListener != null) {
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];

            float gX = x / SensorManager.GRAVITY_EARTH;
            float gY = y / SensorManager.GRAVITY_EARTH;
            float gZ = z / SensorManager.GRAVITY_EARTH;

            // gForce will be close to 1 when there is no movement.
            float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);

            if (gForce > SHAKE_THRESHOLD_GRAVITY) {
                final long now = System.currentTimeMillis();
                // ignore shake events too close to each other (500ms)
                if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now ) {
                    return;
                }

                // reset the shake count after 3 seconds of no shakes
                if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now ) {
                    mShakeCount = 0;
                }

                mShakeTimestamp = now;
                mShakeCount++;

                mListener.onShake(mShakeCount);
            }
        }
    }
}

Inoltre, non dimenticare che è necessario registrare un'istanza di ShakeDetector con SensorManager.

// ShakeDetector initialization
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mShakeDetector = new ShakeDetector();
mShakeDetector.setOnShakeListener(new OnShakeListener() {

    @Override
    public void onShake(int count) {
            handleShakeEvent(count); 
        }
    });

mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);

2
Aggiunta molto bella. Stavo davvero pensando di fare qualcosa di simile, ma era abbastanza buono per il mio cliente così com'era. Ottimo lavoro!
Peterdk,

1
Vorrei cambiare SHAKE_THRESHOLD_GRAVITYa 1.7f per evitare che i lettori di pensare che questa risposta non funziona perché devono tremare abbastanza difficile a causa del valore impostato essendo 2.7F .
ChuongPham,

@Akos Come posso verificare questo modello di agitazione? Come posso archiviare nel database SQLite per scopi di verifica futuri?
sam_k,

1
la countvariabile in onShake ti dice quante volte il dispositivo è stato scosso
Akos Cz

1
Ottimo lavoro, userei SystemClock.elapsedRealtime()piuttosto che System.currentTimeMillis()inizializzare mShakeTimestamp con lo stesso metodo anziché con 0
Massimo

4

Sto sviluppando un'app di rilevamento del movimento e di rilevamento delle vibrazioni per il mio progetto universitario.

Oltre al target originale dell'applicazione, sto dividendo la parte della libreria (responsabile del rilevamento di movimento e vibrazione) dall'app. Il codice è gratuito, disponibile su SourceForge con il nome del progetto "BenderCatch". La documentazione che sto producendo sarà pronta verso metà settembre. http://sf.net/projects/bendercatch

Utilizza un modo più preciso per rilevare la vibrazione: osserva ENTRAMBI la differenza di forza tra SensorEvents E le oscillazioni presenti negli assi X e Y quando si esegue una vibrazione. Può persino emettere un suono (o vibrare) ad ogni oscillazione del movimento.

Sentiti libero di chiedermi di più via e-mail all'indirizzo raffaele [at] terzigno [dot] com


4

Ho scritto un piccolo esempio per rilevare le vibrazioni verticali e orizzontali e mostrare a Toast.

public class Accelerometerka2Activity extends Activity implements SensorEventListener { 
    private float mLastX, mLastY, mLastZ;
    private boolean mInitialized;
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    private final float NOISE = (float) 8.0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mInitialized = false;
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, mAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
    }

    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
    }

    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
    }


    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // can be safely ignored for this demo
    }


    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];
        if (!mInitialized) {
            mLastX = x;
            mLastY = y;
            mLastZ = z;
            mInitialized = true;
        } else {
            float deltaX = Math.abs(mLastX - x);
            float deltaY = Math.abs(mLastY - y);
            float deltaZ = Math.abs(mLastZ - z);
            if (deltaX < NOISE) deltaX = (float)0.0;
            if (deltaY < NOISE) deltaY = (float)0.0;
            if (deltaZ < NOISE) deltaZ = (float)0.0;
            mLastX = x;
            mLastY = y;
            mLastZ = z;
            if (deltaX > deltaY) {
                Toast.makeText(getBaseContext(), "Horizental", Toast.LENGTH_SHORT).show();
            } else if (deltaY > deltaX) {
                Toast.makeText(getBaseContext(), "Vertical", Toast.LENGTH_SHORT).show();
            }
        }
    }
}


4

Ho provato diverse implementazioni, ma vorrei condividere le mie. Utilizza G-forcecome unità per il calcolo della soglia. Rende un po 'più facile capire cosa sta succedendo e anche con l'impostazione di una buona soglia.

Registra semplicemente un aumento della forza G e innesca l'ascoltatore se supera la soglia. Non utilizza soglie di direzione, perché non è proprio necessario se si desidera semplicemente registrare una buona vibrazione.

Naturalmente è necessario la registrazione standard e la registrazione ONU di questo ascoltatore nel Activity.

Inoltre, per verificare quale soglia è necessaria, ti consiglio la seguente app (non sono in alcun modo connesso a tale app)

    public class UmitoShakeEventListener implements SensorEventListener {

    /**
     * The gforce that is necessary to register as shake. (Must include 1G
     * gravity)
     */
    private final float shakeThresholdInGForce = 2.25F;

    private final float gravityEarth = SensorManager.GRAVITY_EARTH;

    private OnShakeListener listener;

    public void setOnShakeListener(OnShakeListener listener) {
        this.listener = listener;
    }

    public interface OnShakeListener {
        public void onShake();
    }

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

    }

    @Override
    public void onSensorChanged(SensorEvent event) {

        if (listener != null) {
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];

            float gX = x / gravityEarth;
            float gY = y / gravityEarth;
            float gZ = z / gravityEarth;

            //G-Force will be 1 when there is no movement. (gravity)
            float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ); 



            if (gForce > shakeThresholdInGForce) {
                listener.onShake();

            }
        }

    }

}

è probabilmente più accurato, ma a spese di pesanti calcoli come le divisioni sqrt e float in OnSensorChanged ... Andrei con gli altri se l'applicazione è già pesante!
Rupps,

Dubito che un po 'di matematica galleggiante sia così pesante in questi giorni. Forse quando eravamo su dispositivi Android 1.6.
Peterdk,

developer.android.com/training/articles/… ... e la tua routine viene chiamata alcune centinaia di volte al secondo. Un ottimo mangiatore di batterie!
Rupps,

Preferisco la leggibilità a un aumento dell'utilizzo della CPU molto ridotto. 2 x niente non è ancora molto. Ma ognuno ha le sue preferenze. :)
Peterdk,

certo, preferisco routine che corrono due volte più velocemente, spesso paga: P
rupps

3

Ecco un altro codice per questo:

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;

   public class AccelerometerListener implements SensorEventListener {

        private SensorManager sensorManager;
        private List<Sensor> sensors;
        private Sensor sensor;
        private long lastUpdate = -1;
        private long currentTime = -1;
        private Main parent;
        private Timer timer;
        private int shakes;
        private static final Handler mHandler = new Handler();

        private float last_x, last_y, last_z;
        private float current_x, current_y, current_z, currenForce;
        private static final int FORCE_THRESHOLD = 500;
        private final int DATA_X = SensorManager.DATA_X;
        private final int DATA_Y = SensorManager.DATA_Y;
        private final int DATA_Z = SensorManager.DATA_Z;

        public AccelerometerListener(Main parent) {
            SensorManager sensorService = (SensorManager) parent
                    .getSystemService(Context.SENSOR_SERVICE);

            this.sensorManager = sensorService;
            if (sensorService == null)
                return;

            this.sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
            if (sensors.size() > 0) {
                sensor = sensors.get(0);
            }

            this.parent = parent;
        }

        public void start() {
            if (sensor == null)
                return;

            sensorManager.registerListener(this, sensor,
                    SensorManager.SENSOR_DELAY_GAME);
        }

        public void stop() {
            if (sensorManager == null)
                return;

            sensorManager.unregisterListener(this);
        }

        public void onAccuracyChanged(Sensor s, int valu) {

        }

        public void onSensorChanged(SensorEvent event) {

            if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
                return;

            currentTime = System.currentTimeMillis();

            if ((currentTime - lastUpdate) > 50) {
                long diffTime = (currentTime - lastUpdate);
                lastUpdate = currentTime;

                current_x = event.values[DATA_X];
                current_y = event.values[DATA_Y];
                current_z = event.values[DATA_Z];

                currenForce = Math.abs(current_x + current_y + current_z - last_x
                        - last_y - last_z)
                        / diffTime * 10000;

                if (currenForce > FORCE_THRESHOLD) {
                    shakeDetected();
                }
                last_x = current_x;
                last_y = current_y;
                last_z = current_z;

            }
        }

        private void shakeDetected() {
            shakes++;

            if (shakes == 1) {
                if (timer != null) {
                    timer.cancel();
                }

                timer = new Timer();
                timer.schedule(new TimerTask() {

                    @Override
                    public void run() {
                        if (shakes > 3) {
                            mHandler.post(new Runnable() {

                                public void run() {
                                    // shake
                                }
                            });
                        }

                        shakes = 0;
                    }
                }, 500);
            }
        }
    }

3
package anywheresoftware.b4a.student;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;

public class ShakeEventListener implements SensorEventListener {

    /*
     * The gForce that is necessary to register as shake.
     * Must be greater than 1G (one earth gravity unit).
     * You can install "G-Force", by Blake La Pierre
     * from the Google Play Store and run it to see how
     *  many G's it takes to register a shake
     */
    private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
    private static int SHAKE_SLOP_TIME_MS = 500;
    private static final int SHAKE_COUNT_RESET_TIME_MS = 1000;

    private OnShakeListener mListener;
    private long mShakeTimestamp;
    private int mShakeCount;

    public void setOnShakeListener(OnShakeListener listener) {
        this.mListener = listener;
    }

    public interface OnShakeListener {
        public void onShake(int count);
    }

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

    @Override
    public void onSensorChanged(SensorEvent event) {

        if (mListener != null) {
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];

            float gX = x / SensorManager.GRAVITY_EARTH;
            float gY = y / SensorManager.GRAVITY_EARTH;
            float gZ = z / SensorManager.GRAVITY_EARTH;

            // gForce will be close to 1 when there is no movement.
            float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);

            if (gForce > SHAKE_THRESHOLD_GRAVITY) {
                final long now = System.currentTimeMillis();
                // ignore shake events too close to each other (500ms)
                if (mShakeTimestamp + getSHAKE_SLOP_TIME_MS() > now) {
                    return;
                }

                // reset the shake count after 3 seconds of no shakes
                if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
                    mShakeCount = 0;
                }

                mShakeTimestamp = now;
                mShakeCount++;

                mListener.onShake(mShakeCount);
            }
        }
    }

    private long getSHAKE_SLOP_TIME_MS() {
        // TODO Auto-generated method stub
        return SHAKE_SLOP_TIME_MS;
    }

    public void setSHAKE_SLOP_TIME_MS(int sHAKE_SLOP_TIME_MS) {
        SHAKE_SLOP_TIME_MS = sHAKE_SLOP_TIME_MS;
    }   

}

3
 package com.example.shakingapp;

import android.app.Activity;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;


public class MainActivity extends Activity implements SensorEventListener {
  private SensorManager sensorManager;
  private boolean color = false;
  private View view;
  private long lastUpdate;


/** Called when the activity is first created. */

  @Override
  public void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    view = findViewById(R.id.textView);
    view.setBackgroundColor(Color.GREEN);

    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    lastUpdate = System.currentTimeMillis();
  }

  @Override
  public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
      getAccelerometer(event);
    }

  }

  private void getAccelerometer(SensorEvent event) {
    float[] values = event.values;
    // Movement
    float x = values[0];
    float y = values[1];
    float z = values[2];

    System.out.println(x);
    System.out.println(y);
    System.out.println(z);
    System.out.println(SensorManager.GRAVITY_EARTH );

    float accelationSquareRoot = (x * x + y * y + z * z)
        / (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);

    long actualTime = System.currentTimeMillis();
    if (accelationSquareRoot >= 2) //
    {
      if (actualTime - lastUpdate < 200) {
        return;
      }
      lastUpdate = actualTime;
      Toast.makeText(this, "Device was shuffed "+accelationSquareRoot, Toast.LENGTH_SHORT)
          .show();
      if (color) {
        view.setBackgroundColor(Color.GREEN);

      } else {
        view.setBackgroundColor(Color.RED);
      }
      color = !color;
    }
  }

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

  }

  @Override
  protected void onResume() {
    super.onResume();
    // register this class as a listener for the orientation and
    // accelerometer sensors
    sensorManager.registerListener(this,
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
        SensorManager.SENSOR_DELAY_NORMAL);
  }

  @Override
  protected void onPause() {
    // unregister listener
    super.onPause();
    sensorManager.unregisterListener(this);
  }
} 

2

Shaker.java

    import java.util.ArrayList;
    import android.content.Context;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;

    public class Shaker implements SensorEventListener{

        private static final String SENSOR_SERVICE = Context.SENSOR_SERVICE;
        private SensorManager sensorMgr;
        private Sensor mAccelerometer;
        private boolean accelSupported;
        private long timeInMillis;
        private long threshold;
        private OnShakerTreshold listener;
        ArrayList<Float> valueStack;

        public Shaker(Context context, OnShakerTreshold listener, long timeInMillis, long threshold) {
            try {
                this.timeInMillis = timeInMillis;
                this.threshold = threshold;
                this.listener = listener;
                if (timeInMillis<100){
                    throw new Exception("timeInMillis < 100ms");
                }
                valueStack = new ArrayList<Float>((int)(timeInMillis/100));
                sensorMgr = (SensorManager) context.getSystemService(SENSOR_SERVICE);
                mAccelerometer = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

            } catch (Exception e){
                e.printStackTrace();
            }
        }

        public void start() {
            try {
                accelSupported = sensorMgr.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); 
                if (!accelSupported) {
                    stop();
                    throw new Exception("Sensor is not supported");
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }

        public void stop(){
            try {
                sensorMgr.unregisterListener(this, mAccelerometer);
            } catch (Exception e){
                e.printStackTrace();
            }
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                stop();
            } catch (Exception e){
                e.printStackTrace();
            }
            super.finalize();
        }

        long lastUpdate = 0;
        private float last_x;
        private float last_y;
        private float last_z;

public void onSensorChanged(SensorEvent event) {
    try {
        if (event.sensor == mAccelerometer) {
            long curTime = System.currentTimeMillis();
            if ((curTime-lastUpdate)>getNumberOfMeasures()){

                lastUpdate = System.currentTimeMillis();
                float[] values = event.values;
                if (valueStack.size()>(int)getNumberOfMeasures())
                    valueStack.remove(0);
                float x = (int)(values[SensorManager.DATA_X]);
                float y = (int)(values[SensorManager.DATA_Y]);
                float z = (int)(values[SensorManager.DATA_Z]);
                float speed = Math.abs((x+y+z) - (last_x + last_y + last_z));

                valueStack.add(speed);

                String posText = String.format("X:%4.0f Y:%4.0f Z:%4.0f", (x-last_x), (y-last_y), (z-last_z));

                last_x = (x);
                last_y = (y);
                last_z = (z);

                float sumOfValues = 0;
                float avgOfValues = 0;

                for (float f : valueStack){
                        sumOfValues = (sumOfValues+f);
                }
                avgOfValues = sumOfValues/(int)getNumberOfMeasures();

                if (avgOfValues>=threshold){
                    listener.onTreshold();
                    valueStack.clear();
                }

                System.out.println(String.format("M: %+4d A: %5.0f V: %4.0f %s", valueStack.size(),avgOfValues,speed,posText));

            }
        }
    } catch (Exception e){
        e.printStackTrace();
    }
}


        private long getNumberOfMeasures() {
            return timeInMillis/100;
        }

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

        public interface OnShakerTreshold {
            public void onTreshold();
        }
    }

MainActivity.java

public class MainActivity extends Activity implements OnShakerTreshold{


    private Shaker s;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        s = new Shaker(getApplicationContext(), this, 5000, 20);
        // 5000 = 5 second of shaking
        // 20 = minimal threshold (very angry shaking :D)
        // beware screen rotation reset counter
    }

    @Override
    protected void onResume() {
        s.start();
        super.onResume();
    }

    @Override
    protected void onPause() {
        s.stop();
        super.onPause();
    }

    public void onTreshold() {
        System.out.println("FIRE LISTENER");
        RingtoneManager.getRingtone(getApplicationContext(), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)).play();
    }


}

Divertiti.


correzione del collegamento a "contatore di ripristino della rotazione dello schermo"
Mertuarez

2
// Need to implement SensorListener
public class ShakeActivity extends Activity implements SensorListener {
// For shake motion detection.
private SensorManager sensorMgr;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private static final int SHAKE_THRESHOLD = 800;

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start motion detection
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
boolean accelSupported = sensorMgr.registerListener(this,
    SensorManager.SENSOR_ACCELEROMETER,
    SensorManager.SENSOR_DELAY_GAME);

if (!accelSupported) {
    // on accelerometer on this device
    sensorMgr.unregisterListener(this,
            SensorManager.SENSOR_ACCELEROMETER);
}
}

protected void onPause() {
if (sensorMgr != null) {
    sensorMgr.unregisterListener(this,
            SensorManager.SENSOR_ACCELEROMETER);
    sensorMgr = null;
    }
super.onPause();
}

public void onAccuracyChanged(int arg0, int arg1) {
// TODO Auto-generated method stub
}

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) {
        // yes, this is a shake action! Do something about it!
    }
    last_x = x;
    last_y = y;
    last_z = z;
    }
}
}
}

Questo codice contiene codice obsoleto. ad es. SensorManager.SENSOR_ACCELEROMETER.
fiacobelli,

2

È necessario abbonarsi come SensorEventListenere ottenere i accelerometerdati. Una volta che lo hai, dovresti monitorare l'improvviso cambio di direzione (segno) di accelerazione su un certo asse. Sarebbe una buona indicazione per il 'shake'movimento del dispositivo.


1

Lavorare con me v. Good Reference

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

0

Potresti voler provare tinybus open source . Con esso il rilevamento delle vibrazioni è facile come questo.

public class MainActivity extends Activity {

    private Bus mBus;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...

        // Create a bus and attach it to activity
        mBus = TinyBus.from(this).wire(new ShakeEventWire());
    }

    @Subscribe
    public void onShakeEvent(ShakeEvent event) {
        Toast.makeText(this, "Device has been shaken", 
                Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onStart() {
        super.onStart();
        mBus.register(this);
    }

    @Override
    protected void onStop() {
        mBus.unregister(this);
        super.onStop();
    }
}

Utilizza sismico per il rilevamento di vibrazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.