mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-08 22:42:05 +08:00
Updating shake handling for Android in ShakeDetector and DevSupportManagerImpl
Summary: If you use a ShakeDetector, you can specify the minimum number of shakes required to trigger a shake handler. Otherwise, the minimum number of required shakes is set to 1 by default. Reviewed By: achen1 Differential Revision: D5155604 fbshipit-source-id: 5073fa37d4c223eb18e85b5e850b95d37136e3d2
This commit is contained in:
committed by
Facebook Github Bot
parent
9e026ec358
commit
aeccbd6906
@@ -150,6 +150,7 @@ public class ReactInstanceManager {
|
||||
private final boolean mLazyViewManagersEnabled;
|
||||
private final boolean mSetupReactContextInBackgroundEnabled;
|
||||
private final boolean mUseSeparateUIBackgroundThread;
|
||||
private final int mMinNumShakes;
|
||||
|
||||
private final ReactInstanceDevCommandsHandler mDevInterface =
|
||||
new ReactInstanceDevCommandsHandler() {
|
||||
@@ -222,7 +223,8 @@ public class ReactInstanceManager {
|
||||
boolean lazyNativeModulesEnabled,
|
||||
boolean lazyViewManagersEnabled,
|
||||
boolean setupReactContextInBackgroundEnabled,
|
||||
boolean useSeparateUIBackgroundThread) {
|
||||
boolean useSeparateUIBackgroundThread,
|
||||
int minNumShakes) {
|
||||
|
||||
initializeSoLoaderIfNecessary(applicationContext);
|
||||
|
||||
@@ -240,7 +242,8 @@ public class ReactInstanceManager {
|
||||
mDevInterface,
|
||||
mJSMainModuleName,
|
||||
useDeveloperSupport,
|
||||
redBoxHandler);
|
||||
redBoxHandler,
|
||||
minNumShakes);
|
||||
mBridgeIdleDebugListener = bridgeIdleDebugListener;
|
||||
mLifecycleState = initialLifecycleState;
|
||||
mUIImplementationProvider = uiImplementationProvider;
|
||||
@@ -251,6 +254,7 @@ public class ReactInstanceManager {
|
||||
mLazyViewManagersEnabled = lazyViewManagersEnabled;
|
||||
mSetupReactContextInBackgroundEnabled = setupReactContextInBackgroundEnabled;
|
||||
mUseSeparateUIBackgroundThread = useSeparateUIBackgroundThread;
|
||||
mMinNumShakes = minNumShakes;
|
||||
|
||||
// Instantiate ReactChoreographer in UI thread.
|
||||
ReactChoreographer.initialize();
|
||||
@@ -685,6 +689,10 @@ public class ReactInstanceManager {
|
||||
return mLifecycleState;
|
||||
}
|
||||
|
||||
public int getMinNumShakes() {
|
||||
return mMinNumShakes;
|
||||
}
|
||||
|
||||
@ThreadConfined(UI)
|
||||
private void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) {
|
||||
synchronized (mAttachedRootViews) {
|
||||
|
||||
@@ -44,6 +44,7 @@ public class ReactInstanceManagerBuilder {
|
||||
protected boolean mLazyViewManagersEnabled;
|
||||
protected boolean mSetupReactContextInBackground;
|
||||
protected boolean mUseSeparateUIBackgroundThread;
|
||||
protected int mMinNumShakes = 1;
|
||||
|
||||
/* package protected */ ReactInstanceManagerBuilder() {
|
||||
}
|
||||
@@ -200,6 +201,11 @@ public class ReactInstanceManagerBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReactInstanceManagerBuilder setMinNumShakes(int minNumShakes) {
|
||||
mMinNumShakes = minNumShakes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new {@link ReactInstanceManager}.
|
||||
* Before calling {@code build}, the following must be called:
|
||||
@@ -247,6 +253,7 @@ public class ReactInstanceManagerBuilder {
|
||||
mLazyNativeModulesEnabled,
|
||||
mLazyViewManagersEnabled,
|
||||
mSetupReactContextInBackground,
|
||||
mUseSeparateUIBackgroundThread);
|
||||
mUseSeparateUIBackgroundThread,
|
||||
mMinNumShakes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ package com.facebook.react.common;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
@@ -23,11 +25,21 @@ import com.facebook.infer.annotation.Assertions;
|
||||
*/
|
||||
public class ShakeDetector implements SensorEventListener {
|
||||
|
||||
private static final int MAX_SAMPLES = 25;
|
||||
private static final int MIN_TIME_BETWEEN_SAMPLES_MS = 20;
|
||||
private static final int VISIBLE_TIME_RANGE_MS = 500;
|
||||
//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 =
|
||||
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;
|
||||
private static final int PERCENT_OVER_THRESHOLD_FOR_SHAKE = 66;
|
||||
//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 =
|
||||
TimeUnit.NANOSECONDS.convert(3, TimeUnit.SECONDS);
|
||||
|
||||
public static interface ShakeListener {
|
||||
void onShake();
|
||||
@@ -38,11 +50,20 @@ 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;
|
||||
|
||||
public ShakeDetector(ShakeListener listener) {
|
||||
this(listener, 1);
|
||||
}
|
||||
|
||||
public ShakeDetector(ShakeListener listener, int minNumShakes) {
|
||||
mShakeListener = listener;
|
||||
mMinNumShakes = minNumShakes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +78,9 @@ public class ShakeDetector implements SensorEventListener {
|
||||
mCurrentIndex = 0;
|
||||
mMagnitudes = new double[MAX_SAMPLES];
|
||||
mTimestamps = new long[MAX_SAMPLES];
|
||||
|
||||
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
|
||||
mNumShakes = 0;
|
||||
mLastShakeTimestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +96,7 @@ public class ShakeDetector implements SensorEventListener {
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent sensorEvent) {
|
||||
if (sensorEvent.timestamp - mLastTimestamp < MIN_TIME_BETWEEN_SAMPLES_MS) {
|
||||
if (sensorEvent.timestamp - mLastTimestamp < MIN_TIME_BETWEEN_SAMPLES_NS) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -106,16 +128,27 @@ public class ShakeDetector implements SensorEventListener {
|
||||
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_MS) {
|
||||
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) {
|
||||
mShakeListener.onShake();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,14 +32,16 @@ public class DevSupportManagerFactory {
|
||||
Context applicationContext,
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate) {
|
||||
boolean enableOnCreate,
|
||||
int minNumShakes) {
|
||||
|
||||
return create(
|
||||
applicationContext,
|
||||
reactInstanceCommandsHandler,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
null);
|
||||
null,
|
||||
minNumShakes);
|
||||
}
|
||||
|
||||
public static DevSupportManager create(
|
||||
@@ -47,7 +49,8 @@ public class DevSupportManagerFactory {
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler) {
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
int minNumShakes) {
|
||||
if (!enableOnCreate) {
|
||||
return new DisabledDevSupportManager();
|
||||
}
|
||||
@@ -68,13 +71,15 @@ public class DevSupportManagerFactory {
|
||||
ReactInstanceDevCommandsHandler.class,
|
||||
String.class,
|
||||
boolean.class,
|
||||
RedBoxHandler.class);
|
||||
RedBoxHandler.class,
|
||||
int.class);
|
||||
return (DevSupportManager) constructor.newInstance(
|
||||
applicationContext,
|
||||
reactInstanceCommandsHandler,
|
||||
packagerPathForJSBundleName,
|
||||
true,
|
||||
redBoxHandler);
|
||||
redBoxHandler,
|
||||
minNumShakes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Requested enabled DevSupportManager, but DevSupportManagerImpl class was not found" +
|
||||
@@ -82,5 +87,4 @@ public class DevSupportManagerFactory {
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,19 @@
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -34,8 +47,8 @@ import com.facebook.react.bridge.JavaJSExecutor;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.DebugServerException;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.ShakeDetector;
|
||||
import com.facebook.react.common.futures.SimpleSettableFuture;
|
||||
import com.facebook.react.devsupport.DevServerHelper.PackagerCommandListener;
|
||||
@@ -44,22 +57,8 @@ import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
import com.facebook.react.devsupport.interfaces.StackFrame;
|
||||
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
|
||||
import com.facebook.react.packagerconnection.JSPackagerClient;
|
||||
import com.facebook.react.packagerconnection.Responder;
|
||||
import com.facebook.react.packagerconnection.RequestHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import com.facebook.react.packagerconnection.Responder;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
@@ -172,13 +171,15 @@ public class DevSupportManagerImpl implements
|
||||
Context applicationContext,
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate) {
|
||||
boolean enableOnCreate,
|
||||
int minNumShakes) {
|
||||
|
||||
this(applicationContext,
|
||||
reactInstanceCommandsHandler,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
null);
|
||||
null,
|
||||
minNumShakes);
|
||||
}
|
||||
|
||||
public DevSupportManagerImpl(
|
||||
@@ -186,8 +187,8 @@ public class DevSupportManagerImpl implements
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler) {
|
||||
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
int minNumShakes) {
|
||||
mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
|
||||
mApplicationContext = applicationContext;
|
||||
mJSAppBundleName = packagerPathForJSBundleName;
|
||||
@@ -200,7 +201,7 @@ public class DevSupportManagerImpl implements
|
||||
public void onShake() {
|
||||
showDevOptionsDialog();
|
||||
}
|
||||
});
|
||||
}, minNumShakes);
|
||||
|
||||
// Prepare reload APP broadcast receiver (will be registered/unregistered from #reload)
|
||||
mReloadAppBroadcastReceiver = new BroadcastReceiver() {
|
||||
|
||||
Reference in New Issue
Block a user