So I’ve been playing around with Android and have a little app that I wanted the user to be able to shake the phone and have something happen. I did some digging and the following is a tutorial on how to setup a shake listener to capture a shake and then do whatever you want.
This is by no means something that I’ve created, I just used examples that I found on stackoverflow.com. Also, this uses G-force to calculate the shake threshold. Many thanks to Peterdk and Akos Cz for their input and answer for this solution. Peterdk recommended using the G-Force app by Blake La Pierre on Google Play Store if you want to get the actual G-force value on your phone and tweak it in the code below.
Long story short, there are 5 things that need to happen to get this to work:
- Create a new class named ShakeDetector
- Define variables for sensor manager, shake detector and accelerometer
- Add/register the sensor manager and listener in the onCreate() method in your activity
- Configure onResume and onPause to activate/deactivate the accelerometer
- Edit the AndroidManifest.xml file to require the device to have an accelerometer
Here’s how to do it all:
Step 1
Create a new class named ShakeDetector and put the following code in it:
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).
* 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 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);
}
}
}
}
I get a warning in Eclipse about the sqrt on line 50 of the code above saying “Use java.lang.Math#sqrt instead of android.util.FloatMath#sqrt() since it is faster as of API 8”, but I choose to ignore it.
Step 2
At the beginning of your activity, declare the following variables:
// The following are used for the shake detection private SensorManager mSensorManager; private Sensor mAccelerometer; private ShakeDetector mShakeDetector;
Step 3
Now, in your activity, paste the following in the onCreate() method:
// 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) {
/*
* The following method, "handleShakeEvent(count):" is a stub //
* method you would use to setup whatever you want done once the
* device has been shook.
*/
handleShakeEvent(count);
}
});
Take care of any missing import statements (ctrl+shift+o in Eclipse). Create your own handleShakeEvent method to do what you want when a shake is detected. Or, remove the stub reference to handleShakeEvent(count); in the code above and create your own method or add what you want in its place.
Step 4
Modify (or add) onResume and onPause to include the following line:
@Override
public void onResume() {
super.onResume();
// Add the following line to register the Session Manager Listener onResume
mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
}
@Override
public void onPause() {
// Add the following line to unregister the Sensor Manager onPause
mSensorManager.unregisterListener(mShakeDetector);
super.onPause();
}
Step 5
I also added the following in my AndroidManifest.xml to make sure the phone has an accelerometer (it goes right after the <uses-sdk /> section):
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
There you have it. I hope this helps!
Sources:
Leave a Reply
You must be logged in to post a comment.