123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- package com.reactnativenavigation.activities;
-
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.content.res.Configuration;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Handler;
- import android.provider.Settings;
- import android.support.annotation.CallSuper;
- import android.support.v4.widget.DrawerLayout;
- import android.support.v7.app.ActionBarDrawerToggle;
- import android.support.v7.app.AppCompatActivity;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.widget.EditText;
- import android.widget.FrameLayout;
- import android.widget.Toast;
-
- import com.facebook.common.logging.FLog;
- import com.facebook.react.ReactInstanceManager;
- import com.facebook.react.ReactPackage;
- import com.facebook.react.ReactRootView;
- import com.facebook.react.bridge.Arguments;
- import com.facebook.react.bridge.ReadableMap;
- import com.facebook.react.bridge.WritableMap;
- import com.facebook.react.common.ReactConstants;
- import com.facebook.react.devsupport.DevServerHelper;
- import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
- import com.facebook.react.shell.MainReactPackage;
- import com.reactnativenavigation.BuildConfig;
- import com.reactnativenavigation.controllers.ModalController;
- import com.reactnativenavigation.core.RctManager;
- import com.reactnativenavigation.core.objects.Button;
- import com.reactnativenavigation.core.objects.Drawer;
- import com.reactnativenavigation.core.objects.Screen;
- import com.reactnativenavigation.modal.RnnModal;
- import com.reactnativenavigation.packages.RnnPackage;
- import com.reactnativenavigation.utils.ContextProvider;
- import com.reactnativenavigation.utils.StyleHelper;
- import com.reactnativenavigation.views.RnnToolBar;
- import com.reactnativenavigation.views.ScreenStack;
-
- import java.util.Arrays;
- import java.util.List;
-
- import javax.annotation.Nullable;
-
- public abstract class BaseReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
-
- protected static final String KEY_ANIMATED = "animated";
- protected static final String KEY_BADGE = "badge";
- protected static final String KEY_HIDDEN = "hidden";
- protected static final String KEY_SIDE = "side";
- protected static final String KEY_TAB_INDEX = "tabIndex";
- protected static final String KEY_TITLE = "title";
- protected static final String KEY_TO = "to";
- private static final String TAG = "BaseReactActivity";
- private static final String REDBOX_PERMISSION_MESSAGE =
- "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
-
- @Nullable
- protected ReactInstanceManager mReactInstanceManager;
- private boolean mDoRefresh = false;
- private Menu mMenu;
- protected RnnToolBar mToolbar;
- protected ActionBarDrawerToggle mDrawerToggle;
- protected DrawerLayout mDrawerLayout;
- protected ScreenStack mDrawerStack;
-
- /**
- * Returns the name of the bundle in assets. If this is null, and no file path is specified for
- * the bundle, the app will only work with {@code getUseDeveloperSupport} enabled and will
- * always try to load the JS bundle from the packager server.
- * e.g. "index.android.bundle"
- */
- @Nullable
- public String getBundleAssetName() {
- return "index.android.bundle";
- }
-
- /**
- * Returns a custom path of the bundle file. This is used in cases the bundle should be loaded
- * from a custom path. By default it is loaded from Android assets, from a path specified
- * by {getBundleAssetName}.
- * e.g. "file://sdcard/myapp_cache/index.android.bundle"
- */
- @Nullable
- public String getJSBundleFile() {
- return null;
- }
-
- /**
- * Returns the name of the main module. Determines the URL used to fetch the JS bundle
- * from the packager server. It is only used when dev support is enabled.
- * This is the first file to be executed once the {@link ReactInstanceManager} is created.
- * e.g. "index.android"
- */
- public String getJSMainModuleName() {
- return "index.android";
- }
-
- /**
- * Returns the launchOptions which will be passed to the {@link ReactInstanceManager}
- * when the application is started. By default, this will return null and an empty
- * object will be passed to your top level component as its initial props.
- * If your React Native application requires props set outside of JS, override
- * this method to return the Android.os.Bundle of your desired initial props.
- */
- @Nullable
- protected Bundle getLaunchOptions() {
- return null;
- }
-
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- * e.g. "MoviesApp"
- */
- protected String getMainComponentName() {
- return "";
- }
-
- /**
- * Returns whether dev mode should be enabled. This enables e.g. the dev menu.
- */
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
-
- /**
- * Returns a list of {@link ReactPackage} used by the app.
- * You'll most likely want to return at least the {@code MainReactPackage}.
- * If your app uses additional views or modules besides the default ones,
- * you'll want to include more packages here.
- */
- public List<ReactPackage> getPackages() {
- return Arrays.asList(
- new MainReactPackage(),
- new RnnPackage()
- );
- }
-
- /**
- * A subclass may override this method if it needs to use a custom {@link ReactRootView}.
- */
- protected ReactRootView createRootView() {
- return new ReactRootView(this);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ContextProvider.setActivityContext(this);
- mReactInstanceManager = createReactInstanceManager();
- handleOnCreate();
-
- }
-
- /**
- * A subclass may override this method if it needs to use a custom instance.
- */
- protected ReactInstanceManager createReactInstanceManager() {
- return getReactInstanceManager();
- }
-
- protected ReactInstanceManager getReactInstanceManager() {
- RctManager rctManager = RctManager.getInstance();
- if (!rctManager.isInitialized()) {
- rctManager.init(this);
- }
- return rctManager.getReactInstanceManager();
- }
-
- @CallSuper
- protected void handleOnCreate() {
- permissionToShowRedboxIfNeeded();
- }
-
- private void permissionToShowRedboxIfNeeded() {
- if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23 && !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();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- ContextProvider.setActivityContext(this);
-
- if (mReactInstanceManager != null) {
- mReactInstanceManager.onHostResume(this, this);
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- if (mReactInstanceManager != null) {
- mReactInstanceManager.onHostPause();
- }
-
- ContextProvider.clearActivityContext();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- // Destroy react instance manager only if there are no resumed react activities
- BaseReactActivity activity = ContextProvider.getActivityContext();
- if (mReactInstanceManager != null && (activity == null || activity.isFinishing())) {
- Log.i(TAG, "Destroying ReactInstanceManager");
- mReactInstanceManager.onHostDestroy();
- RctManager.getInstance().onDestroy();
- } else {
- Log.d(TAG, "Not destroying ReactInstanceManager");
- }
- }
-
- @CallSuper
- public void push(Screen screen) {
- StyleHelper.updateStyles(mToolbar, screen);
- if (mToolbar != null) {
- mToolbar.update(screen);
-
- if (getCurrentNavigatorId().equals(screen.navigatorId) &&
- getScreenStackSize() >= 1) {
- mToolbar.setNavUpButton(screen);
- }
- }
- }
-
- @CallSuper
- public Screen pop(String navigatorId) {
- if (mToolbar != null &&
- getCurrentNavigatorId().equals(navigatorId) &&
- getScreenStackSize() <= 2) {
- mToolbar.setNavUpButton();
- }
-
- return null;
- }
-
- @CallSuper
- public Screen popToRoot(String navigatorId) {
- if (mToolbar != null) {
- mToolbar.setNavUpButton();
- }
-
- return null;
- }
-
- @CallSuper
- public Screen resetTo(Screen screen) {
- StyleHelper.updateStyles(mToolbar, screen);
- if (mToolbar != null) {
- mToolbar.setNavUpButton();
- }
-
- return null;
- }
-
- protected abstract String getCurrentNavigatorId();
-
- @CallSuper
- public Screen getCurrentScreen() {
- ModalController modalController = ModalController.getInstance();
- if (modalController.isModalDisplayed()) {
- RnnModal modal = modalController.get();
- assert modal != null;
- return modal.getCurrentScreen();
- }
-
- return null;
- }
-
- public abstract int getScreenStackSize();
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mDrawerToggle != null) {
- mDrawerToggle.onConfigurationChanged(newConfig);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- mMenu = menu;
- Screen currentScreen = getCurrentScreen();
- if (mToolbar != null && currentScreen != null) {
- mToolbar.setupToolbarButtonsAsync(currentScreen);
- }
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (mDrawerToggle != null &&
- getScreenStackSize() == 1 &&
- mDrawerToggle.onOptionsItemSelected(item)) {
- return true;
- }
-
- if (item.getItemId() == android.R.id.home) {
- onBackPressed();
- } else {
- String eventId = Button.getButtonEventId(item);
- assert eventId != null;
-
- WritableMap params = Arguments.createMap();
- RctManager.getInstance().sendEvent(eventId, getCurrentScreen(), params);
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onPostCreate(Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
- if (mDrawerToggle != null) {
- mDrawerToggle.syncState();
- }
- }
-
- public Menu getMenu() {
- return mMenu;
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mReactInstanceManager != null) {
- mReactInstanceManager.onActivityResult(requestCode, resultCode, data);
- }
- }
-
- @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)) {
- // Enable double-tap-R-to-reload
- 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);
- }
-
- /**
- * Called after bundle was reloaded. This is a good chance to clean up previously connected react views.
- */
- public void onJSBundleReloaded() {
- removeAllReactViews();
- }
-
- protected abstract void removeAllReactViews();
-
- @Override
- public void onBackPressed() {
- if (getScreenStackSize() > 1) {
- pop(getCurrentNavigatorId());
- } else {
- if (mReactInstanceManager != null) {
- mReactInstanceManager.onBackPressed();
- } else {
- super.onBackPressed();
- }
- }
- }
-
- @Override
- public void invokeDefaultOnBackPressed() {
- super.onBackPressed();
- }
-
- protected void setupDrawer(Screen screen, Drawer drawer, int drawerFrameId, int drawerLayoutId) {
- if (drawer == null || drawer.left == null) {
- return;
- }
-
- mDrawerStack = new ScreenStack(this);
- FrameLayout drawerFrame = (FrameLayout) findViewById(drawerFrameId);
- drawerFrame.addView(mDrawerStack);
- mDrawerStack.push(drawer.left);
-
- mDrawerLayout = (DrawerLayout) findViewById(drawerLayoutId);
- mDrawerToggle = mToolbar.setupDrawer(mDrawerLayout, drawer.left, screen);
- }
-
- public void setNavigationButtons(ReadableMap buttons) {
- if (mToolbar == null) {
- return;
- }
- getCurrentScreen().setButtons(buttons);
- mToolbar.setupToolbarButtonsAsync(getCurrentScreen());
- }
-
- public void setNavigationTitle(ReadableMap title) {
- if (mToolbar == null) {
- return;
- }
-
- mToolbar.setTitle(title.getString(KEY_TITLE));
- }
-
- public void toggleNavigationBar(ReadableMap params) {
- if (mToolbar == null) {
- return;
- }
-
- boolean hide = params.getBoolean(KEY_HIDDEN);
- boolean animated = params.getBoolean(KEY_ANIMATED);
- if (hide) {
- mToolbar.hideToolbar(animated);
- } else {
- mToolbar.showToolbar(animated);
- }
- }
-
- public void toggleDrawer(ReadableMap params) {
- if (mToolbar == null || mDrawerToggle == null) {
- return;
- }
-
- boolean animated = params.getBoolean(KEY_ANIMATED);
- String side = params.getString(KEY_SIDE);
- String to = params.getString(KEY_TO);
- switch (to) {
- case "open":
- mToolbar.showDrawer(animated);
- break;
- case "closed":
- mToolbar.hideDrawer(animated);
- break;
- default:
- mToolbar.toggleDrawer(animated);
- break;
- }
- }
- }
|