Created
December 16, 2015 15:28
-
-
Save mkonicek/aa7997919c83740c66e6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.facebook.react.shell; | |
import javax.annotation.Nullable; | |
import java.util.Collections; | |
import java.util.List; | |
import android.content.Intent; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.os.Handler; | |
import android.provider.Settings; | |
import android.support.v4.app.FragmentActivity; | |
import android.view.KeyEvent; | |
import android.widget.EditText; | |
import android.widget.Toast; | |
import com.facebook.common.logging.FLog; | |
import com.facebook.infer.annotation.Assertions; | |
import com.facebook.react.LifecycleState; | |
import com.facebook.react.ReactInstanceManager; | |
import com.facebook.react.ReactPackage; | |
import com.facebook.react.ReactRootView; | |
import com.facebook.react.common.ReactConstants; | |
import com.facebook.react.common.build.ReactBuildConfig; | |
import com.facebook.react.devsupport.DevOptionHandler; | |
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; | |
import com.facebook.react.uimanager.UIImplementationProvider; | |
import com.facebook.systrace.Systrace; | |
import com.facebook.systrace.SystraceMessage; | |
/** | |
* Base for an Activity that hosts a ReactApplicationFragment and wants JS debugging features, | |
* including FPS, reloading and debugging. | |
*/ | |
public abstract class ReactActivity extends FragmentActivity | |
implements DefaultHardwareBackBtnHandler { | |
private static final String EXTRA_JS_INITIAL_PROPS = "initial_props"; | |
private static final String REDBOX_PERMISSION_MESSAGE = | |
"Overlay permissions needs to be granted in order for react native apps to run in dev mode"; | |
private @Nullable ReactRootView mReactRootView; | |
private @Nullable ReactInstanceManager mReactInstanceManager; | |
private LifecycleState mLifecycleState = LifecycleState.BEFORE_RESUME; | |
private boolean mDoRefresh = false; | |
private @Nullable UIImplementationProvider mUIImplementationProvider; | |
protected void setUIImplementationProvider( | |
UIImplementationProvider uiImplementationProvider) { | |
mUIImplementationProvider = uiImplementationProvider; | |
} | |
@Override | |
protected void onSaveInstanceState(Bundle outState) { | |
// TODO(5846507): save instance state; not calling super() here causes fragments to *not* be | |
// re-created when restoring the instance | |
} | |
/** | |
* @return the name of the bundle in assets. If this is null, the app will only work with dev | |
* support on and will always try to load the JS bundle from the packager server. | |
* eg. "index.android.bundle" | |
*/ | |
protected abstract @Nullable String getDefaultBundleName(); | |
/** | |
* @return the name of the main module. This is used to determine the URL to fetch the JS bundle | |
* from the packager server and is only used when dev support is enabled. | |
* This is the first file to be executed once the {@code ReactInstanceManager} is created. | |
* eg. "RKJSModules/Apps/Airbourne/AirbourneAppBundle" | |
*/ | |
protected abstract String getDefaultMainModule(); | |
/** | |
* @return the Builder instance to use to create the ReactInstanceManager. | |
*/ | |
protected ReactInstanceManager.Builder getReactInstanceManagerBuilder() { | |
return ReactInstanceManager.builder(); | |
} | |
/** | |
* Additional debug options available in the system menu. | |
* Basic options are always available, see | |
* {@link com.facebook.react.devsupport.DevSupportManager}. | |
*/ | |
protected List<String> getAdditionalDebugOptions() { | |
return Collections.emptyList(); | |
} | |
/** | |
* Method returns a {@link ReactPackage} associated with this class. | |
* A subclass may override this method if it needs more views or modules. | |
* In that case a subclass should return a {@link com.facebook.react.CompositeReactPackage} of | |
* this ReactPackage and its own. | |
*/ | |
protected abstract ReactPackage getPackage(); | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= 23) { | |
// Get permission to show redbox in dev builds. | |
if (!Settings.canDrawOverlays(this)) { | |
Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); | |
startActivity(serviceIntent); | |
FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); | |
Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); | |
} | |
} | |
mReactRootView = new ReactRootView(this); | |
setContentView(mReactRootView); | |
} | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
mLifecycleState = LifecycleState.BEFORE_RESUME; | |
if (mReactInstanceManager != null) { | |
mReactInstanceManager.onPause(); | |
} | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
mLifecycleState = LifecycleState.RESUMED; | |
if (mReactInstanceManager != null) { | |
mReactInstanceManager.onResume(this, this); | |
} | |
} | |
@Override | |
protected void onDestroy() { | |
super.onDestroy(); | |
if (mReactInstanceManager != null) { | |
mReactInstanceManager.onDestroy(); | |
} | |
} | |
@Override | |
public void onActivityResult(int requestCode, int resultCode, Intent data) { | |
if (mReactInstanceManager != null) { | |
mReactInstanceManager.onActivityResult(requestCode, resultCode, data); | |
} | |
} | |
protected void loadApp(String appKey) { | |
SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "loadApp") | |
.arg("appKey", appKey) | |
.flush(); | |
try { | |
Bundle launchOptions = getIntent().getBundleExtra(EXTRA_JS_INITIAL_PROPS); | |
ReactInstanceManager.Builder builder = getReactInstanceManagerBuilder() | |
.setApplication(getApplication()) | |
.setBundleAssetName(getDefaultBundleName()) | |
.setJSMainModuleName(getDefaultMainModule()) | |
.addPackage(getPackage()) | |
.setUseDeveloperSupport(ReactBuildConfig.IS_INTERNAL_BUILD) | |
.setInitialLifecycleState(mLifecycleState) | |
.setUIImplementationProvider(mUIImplementationProvider); | |
mReactInstanceManager = builder.build(); | |
registerAdditionalDebugOptions(); | |
Assertions.assertNotNull(mReactRootView).startReactApplication( | |
mReactInstanceManager, | |
appKey, | |
launchOptions); | |
} finally { | |
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); | |
} | |
} | |
@Override | |
public boolean onKeyUp(int keyCode, KeyEvent event) { | |
if (mReactInstanceManager != null && | |
mReactInstanceManager.getDevSupportManager().getDevSupportEnabled()) { | |
if (keyCode == KeyEvent.KEYCODE_MENU) { | |
mReactInstanceManager.showDevOptionsDialog(); | |
return true; | |
} | |
if (keyCode == KeyEvent.KEYCODE_R && !(getCurrentFocus() instanceof EditText)) { | |
if (mDoRefresh) { | |
mReactInstanceManager.getDevSupportManager().handleReloadJS(); | |
mDoRefresh = false; | |
} else { | |
mDoRefresh = true; | |
new Handler().postDelayed( | |
new Runnable() { | |
@Override | |
public void run() { | |
mDoRefresh = false; | |
} | |
}, | |
200); | |
} | |
} | |
} | |
return super.onKeyUp(keyCode, event); | |
} | |
@Override | |
public void onBackPressed() { | |
if (mReactInstanceManager != null) { | |
mReactInstanceManager.onBackPressed(); | |
} else { | |
super.onBackPressed(); | |
} | |
} | |
@Override | |
public void invokeDefaultOnBackPressed() { | |
super.onBackPressed(); | |
} | |
@Nullable | |
public ReactInstanceManager getReactInstanceManager() { | |
return mReactInstanceManager; | |
} | |
public boolean onAdditionalDevOptionSelected(String option) { | |
return false; | |
} | |
private void registerAdditionalDebugOptions() { | |
List<String> additionalOptions = getAdditionalDebugOptions(); | |
if (additionalOptions == null || additionalOptions.isEmpty()) { | |
// Subclasses should not return null but don't crash if they do | |
return; | |
} | |
for (String option : getAdditionalDebugOptions()) { | |
registerAdditionalDebugOption(option); | |
} | |
} | |
private void registerAdditionalDebugOption(final String additionalDebugOption) { | |
Assertions.assertNotNull(mReactInstanceManager).getDevSupportManager() | |
.addCustomDevOption(additionalDebugOption, new DevOptionHandler() { | |
@Override | |
public void onOptionSelected() { | |
onAdditionalDevOptionSelected(additionalDebugOption); | |
} | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment