Show RN Dev Menu after 2 rage shakes
Reviewed By: achen1 Differential Revision: D5427430 fbshipit-source-id: cac761c550ff2627f1bbbbde9e9b8d3f122bbb45
This commit is contained in:
parent
1728a866ef
commit
794dddc5bd
|
@ -24,22 +24,17 @@ import com.facebook.infer.annotation.Assertions;
|
||||||
* Listens for the user shaking their phone. Allocation-less once it starts listening.
|
* Listens for the user shaking their phone. Allocation-less once it starts listening.
|
||||||
*/
|
*/
|
||||||
public class ShakeDetector implements SensorEventListener {
|
public class ShakeDetector implements SensorEventListener {
|
||||||
|
// Collect sensor data in this interval (nanoseconds)
|
||||||
//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)
|
|
||||||
private static final long MIN_TIME_BETWEEN_SAMPLES_NS =
|
private static final long MIN_TIME_BETWEEN_SAMPLES_NS =
|
||||||
TimeUnit.NANOSECONDS.convert(20, TimeUnit.MILLISECONDS);
|
TimeUnit.NANOSECONDS.convert(20, TimeUnit.MILLISECONDS);
|
||||||
//expected duration of one shake in nanoseconds
|
// Number of nanoseconds to listen for and count shakes (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
|
|
||||||
private static final float SHAKING_WINDOW_NS =
|
private static final float SHAKING_WINDOW_NS =
|
||||||
TimeUnit.NANOSECONDS.convert(3, TimeUnit.SECONDS);
|
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 {
|
public static interface ShakeListener {
|
||||||
void onShake();
|
void onShake();
|
||||||
|
@ -49,11 +44,8 @@ public class ShakeDetector implements SensorEventListener {
|
||||||
|
|
||||||
@Nullable private SensorManager mSensorManager;
|
@Nullable private SensorManager mSensorManager;
|
||||||
private long mLastTimestamp;
|
private long mLastTimestamp;
|
||||||
private int mCurrentIndex;
|
|
||||||
private int mNumShakes;
|
private int mNumShakes;
|
||||||
private long mLastShakeTimestamp;
|
private long mLastShakeTimestamp;
|
||||||
@Nullable private double[] mMagnitudes;
|
|
||||||
@Nullable private long[] mTimestamps;
|
|
||||||
//number of shakes required to trigger onShake()
|
//number of shakes required to trigger onShake()
|
||||||
private int mMinNumShakes;
|
private int mMinNumShakes;
|
||||||
|
|
||||||
|
@ -75,12 +67,9 @@ public class ShakeDetector implements SensorEventListener {
|
||||||
if (accelerometer != null) {
|
if (accelerometer != null) {
|
||||||
mSensorManager = manager;
|
mSensorManager = manager;
|
||||||
mLastTimestamp = -1;
|
mLastTimestamp = -1;
|
||||||
mCurrentIndex = 0;
|
|
||||||
mMagnitudes = new double[MAX_SAMPLES];
|
|
||||||
mTimestamps = new long[MAX_SAMPLES];
|
|
||||||
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
|
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
|
||||||
mNumShakes = 0;
|
|
||||||
mLastShakeTimestamp = 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
|
@Override
|
||||||
public void onSensorChanged(SensorEvent sensorEvent) {
|
public void onSensorChanged(SensorEvent sensorEvent) {
|
||||||
if (sensorEvent.timestamp - mLastTimestamp < MIN_TIME_BETWEEN_SAMPLES_NS) {
|
if (sensorEvent.timestamp - mLastTimestamp < MIN_TIME_BETWEEN_SAMPLES_NS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assertions.assertNotNull(mTimestamps);
|
|
||||||
Assertions.assertNotNull(mMagnitudes);
|
|
||||||
|
|
||||||
float ax = sensorEvent.values[0];
|
float ax = sensorEvent.values[0];
|
||||||
float ay = sensorEvent.values[1];
|
float ay = sensorEvent.values[1];
|
||||||
float az = sensorEvent.values[2];
|
float az = sensorEvent.values[2] - SensorManager.GRAVITY_EARTH;
|
||||||
|
|
||||||
mLastTimestamp = sensorEvent.timestamp;
|
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);
|
maybeDispatchShake(sensorEvent.timestamp);
|
||||||
|
|
||||||
mCurrentIndex = (mCurrentIndex + 1) % MAX_SAMPLES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -121,34 +144,13 @@ public class ShakeDetector implements SensorEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeDispatchShake(long currentTimestamp) {
|
private void maybeDispatchShake(long currentTimestamp) {
|
||||||
Assertions.assertNotNull(mTimestamps);
|
if (mNumShakes >= 8 * mMinNumShakes) {
|
||||||
Assertions.assertNotNull(mMagnitudes);
|
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) {
|
if (currentTimestamp - mLastShakeTimestamp > SHAKING_WINDOW_NS) {
|
||||||
mNumShakes = 0;
|
reset();
|
||||||
mLastShakeTimestamp = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue