I have an app that needs to detect shake possibly whenever the user has their phone's screen on. I've found plenty of examples of how to detect shake. The example below being the most intriguing so far with use of Google code and adding in the gravity component. My question is, can this code be improved? Shake detection is pretty solid and i'm getting no false positives. I'm mostly concerned with battery life improvement.
private static final int mMinimumForce = 5;
private static final int mShakeFrequency = 500;
private static final int mMovesRequired = 4;
private float[] mGravity = { 0.0f, 0.0f, 0.0f };
private float[] mAcceleration = { 0.0f, 0.0f, 0.0f };
private static final int mXAxis = 0;
private static final int mYAxis = 1;
private static final int mZAxis = 2;
private long mCurrentTime = 0;
private long mLastTime = 0;
private int mMoveCount = 0;
private final float mAlpha = 0.8f;
public void onSensorChanged(SensorEvent event)
{
if(event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
{
return;
}
// Set linear acceleration
// Gravity components of x, y, and z acceleration
mGravity[mXAxis] = mAlpha * mGravity[mXAxis] + (1 - mAlpha) * event.values[mXAxis];
mGravity[mYAxis] = mAlpha * mGravity[mYAxis] + (1 - mAlpha) * event.values[mYAxis];
mGravity[mZAxis] = mAlpha * mGravity[mZAxis] + (1 - mAlpha) * event.values[mZAxis];
// Linear acceleration of x, y, z with gravity effect removed
mAcceleration[mXAxis] = event.values[mXAxis] - mGravity[mXAxis];
mAcceleration[mYAxis] = event.values[mYAxis] - mGravity[mYAxis];
mAcceleration[mZAxis] = event.values[mZAxis] - mGravity[mZAxis];
// Set maximum linear acceleration amongst x, y, z
float maxAcceleration = mAcceleration[mXAxis];
if (mAcceleration[mYAxis] > maxAcceleration)
{
maxAcceleration = mAcceleration[mYAxis];
}
if (mAcceleration[mZAxis] > maxAcceleration)
{
maxAcceleration = mAcceleration[mZAxis];
}
// Process shake
if (maxAcceleration > mMinimumForce)
{
Log.d(TAG, "Shake detected");
mCurrentTime = System.currentTimeMillis();
if (mLastTime == 0)
{
mLastTime = mCurrentTime;
}
long elapsedTime = mCurrentTime - mLastTime;
if (elapsedTime > mShakeFrequency)
{
mLastTime = 0;
mMoveCount = 0;
}
else
{
mMoveCount++;
if (mMoveCount > mMovesRequired)
{
Log.d(TAG, "Shake moves detected: " + mMovesRequired);
// do some work here
mLastTime = 0;
mMoveCount = 0;
}
}
}
}
Google I/O docs have great information on all of your concerns. Here's one such document. https://dl.google.com/io/2009/pres/W_0300_CodingforLife-BatteryLifeThatIs.pdf
Your point on floating point math is correct. While your code doesn't do much as far as calculations, the constant calling of it at high frequency could tax the CPU.
Your point on accelerometer using battery. While each device is different regarding power consumption and this device doesn't use close to what the gyroscope does, it will show a marked difference if used non-stop on a full day of active screen use.
I agree that coding to the highest standards and efficiency is good regardless of if you see a marked difference in battery usage. It's just being a good citizen. If I can get 30 more minutes out of my phone, give it to me!!!
My suggestions on your code, which are really just reflective of Google's recommendations and many you're already speaking about.