Permalink
Browse files

Show RN Dev Menu after 2 rage shakes

Reviewed By: achen1

Differential Revision: D5427430

fbshipit-source-id: cac761c550ff2627f1bbbbde9e9b8d3f122bbb45
  • Loading branch information...
sumkit authored and facebook-github-bot committed Jul 21, 2017
1 parent 1728a86 commit 794dddc5bdeccb31721e7a7f6e9305846c84a5cb
Showing with 55 additions and 53 deletions.
  1. +55 −53 ReactAndroid/src/main/java/com/facebook/react/common/ShakeDetector.java
@@ -24,22 +24,17 @@
* 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 @@
@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 void start(SensorManager manager) {
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,61 +83,74 @@ public void stop() {
}
}
/**
* 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);
maybeDispatchShake(sensorEvent.timestamp);
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;
}
mCurrentIndex = (mCurrentIndex + 1) % MAX_SAMPLES;
maybeDispatchShake(sensorEvent.timestamp);
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
private void maybeDispatchShake(long currentTimestamp) {
Assertions.assertNotNull(mTimestamps);
Assertions.assertNotNull(mMagnitudes);
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 (mNumShakes >= 8 * mMinNumShakes) {
reset();
mShakeListener.onShake();
}
if (currentTimestamp - mLastShakeTimestamp > SHAKING_WINDOW_NS) {
mNumShakes = 0;
mLastShakeTimestamp = 0;
reset();
}
}
}

0 comments on commit 794dddc

Please sign in to comment.