Show RN Dev Menu after 2 rage shakes

Reviewed By: achen1

Differential Revision: D5427430

fbshipit-source-id: cac761c550ff2627f1bbbbde9e9b8d3f122bbb45
This commit is contained in:
Summer Kitahara 2017-07-20 23:50:24 -07:00 committed by Facebook Github Bot
parent 1728a866ef
commit 794dddc5bd
1 changed files with 55 additions and 53 deletions

View File

@ -24,22 +24,17 @@ import com.facebook.infer.annotation.Assertions;
* Listens for the user shaking their phone. Allocation-less once it starts listening.
*/
public class ShakeDetector implements SensorEventListener {
//only record and consider the last MAX_SAMPLES number of data points
private static final int MAX_SAMPLES = 40;
//collect sensor data in this interval (nanoseconds)
// Collect sensor data in this interval (nanoseconds)
private static final long MIN_TIME_BETWEEN_SAMPLES_NS =
TimeUnit.NANOSECONDS.convert(20, TimeUnit.MILLISECONDS);
//expected duration of one shake in nanoseconds
private static final long VISIBLE_TIME_RANGE_NS =
TimeUnit.NANOSECONDS.convert(250, TimeUnit.MILLISECONDS);
//minimum amount of force on accelerometer sensor to constitute a shake
private static final int MAGNITUDE_THRESHOLD = 25;
//this percentage of data points must have at least the force of MAGNITUDE_THRESHOLD
private static final int PERCENT_OVER_THRESHOLD_FOR_SHAKE = 60;
//number of nanoseconds to listen for and count shakes
// Number of nanoseconds to listen for and count shakes (nanoseconds)
private static final float SHAKING_WINDOW_NS =
TimeUnit.NANOSECONDS.convert(3, TimeUnit.SECONDS);
// Required force to constitute a rage shake. Need to multiply gravity by 1.33 because a rage
// shake in one direction should have more force than just the magnitude of free fall.
private static final float REQUIRED_FORCE = SensorManager.GRAVITY_EARTH * 1.33f;
private float mAccelerationX, mAccelerationY, mAccelerationZ;
public static interface ShakeListener {
void onShake();
@ -49,11 +44,8 @@ public class ShakeDetector implements SensorEventListener {
@Nullable private SensorManager mSensorManager;
private long mLastTimestamp;
private int mCurrentIndex;
private int mNumShakes;
private long mLastShakeTimestamp;
@Nullable private double[] mMagnitudes;
@Nullable private long[] mTimestamps;
//number of shakes required to trigger onShake()
private int mMinNumShakes;
@ -75,12 +67,9 @@ public class ShakeDetector implements SensorEventListener {
if (accelerometer != null) {
mSensorManager = manager;
mLastTimestamp = -1;
mCurrentIndex = 0;
mMagnitudes = new double[MAX_SAMPLES];
mTimestamps = new long[MAX_SAMPLES];
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
mNumShakes = 0;
mLastShakeTimestamp = 0;
reset();
}
}
@ -94,26 +83,60 @@ public class ShakeDetector implements SensorEventListener {
}
}
/**
* Reset all variables used to keep track of number of shakes recorded.
*/
private void reset() {
mNumShakes = 0;
mAccelerationX = 0;
mAccelerationY = 0;
mAccelerationZ = 0;
}
/**
* Determine if acceleration applied to sensor is large enough to count as a rage shake.
*
* @param a acceleration in x, y, or z applied to the sensor
* @return true if the magnitude of the force exceeds the minimum required amount of force.
* false otherwise.
*/
private boolean atLeastRequiredForce(float a) {
return Math.abs(a) > REQUIRED_FORCE;
}
/**
* Save data about last shake
* @param timestamp (ns) of last sensor event
*/
private void recordShake(long timestamp) {
mLastShakeTimestamp = timestamp;
mNumShakes++;
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.timestamp - mLastTimestamp < MIN_TIME_BETWEEN_SAMPLES_NS) {
return;
}
Assertions.assertNotNull(mTimestamps);
Assertions.assertNotNull(mMagnitudes);
float ax = sensorEvent.values[0];
float ay = sensorEvent.values[1];
float az = sensorEvent.values[2];
float az = sensorEvent.values[2] - SensorManager.GRAVITY_EARTH;
mLastTimestamp = sensorEvent.timestamp;
mTimestamps[mCurrentIndex] = sensorEvent.timestamp;
mMagnitudes[mCurrentIndex] = Math.sqrt(ax * ax + ay * ay + az * az);
if (atLeastRequiredForce(ax) && ax * mAccelerationX <= 0) {
recordShake(sensorEvent.timestamp);
mAccelerationX = ax;
} else if (atLeastRequiredForce(ay) && ay * mAccelerationY <= 0) {
recordShake(sensorEvent.timestamp);
mAccelerationY = ay;
} else if (atLeastRequiredForce(az) && az * mAccelerationZ <= 0) {
recordShake(sensorEvent.timestamp);
mAccelerationZ = az;
}
maybeDispatchShake(sensorEvent.timestamp);
mCurrentIndex = (mCurrentIndex + 1) % MAX_SAMPLES;
}
@Override
@ -121,34 +144,13 @@ public class ShakeDetector implements SensorEventListener {
}
private void maybeDispatchShake(long currentTimestamp) {
Assertions.assertNotNull(mTimestamps);
Assertions.assertNotNull(mMagnitudes);
if (mNumShakes >= 8 * mMinNumShakes) {
reset();
mShakeListener.onShake();
}
int numOverThreshold = 0;
int total = 0;
for (int i = 0; i < MAX_SAMPLES; i++) {
int index = (mCurrentIndex - i + MAX_SAMPLES) % MAX_SAMPLES;
if (currentTimestamp - mTimestamps[index] < VISIBLE_TIME_RANGE_NS) {
total++;
if (mMagnitudes[index] >= MAGNITUDE_THRESHOLD) {
numOverThreshold++;
}
}
}
if (((double) numOverThreshold) / total > PERCENT_OVER_THRESHOLD_FOR_SHAKE / 100.0) {
if (currentTimestamp - mLastShakeTimestamp >= VISIBLE_TIME_RANGE_NS) {
mNumShakes++;
}
mLastShakeTimestamp = currentTimestamp;
if (mNumShakes >= mMinNumShakes) {
mNumShakes = 0;
mLastShakeTimestamp = 0;
mShakeListener.onShake();
}
}
if (currentTimestamp - mLastShakeTimestamp > SHAKING_WINDOW_NS) {
mNumShakes = 0;
mLastShakeTimestamp = 0;
reset();
}
}
}