private void setupReactContext(ReactApplicationContext reactContext) {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
    UiThreadUtil.assertOnUiThread();
    Assertions.assertCondition(mCurrentReactContext == null);
    mCurrentReactContext = Assertions.assertNotNull(reactContext);
    CatalystInstance catalystInstance =
        Assertions.assertNotNull(reactContext.getCatalystInstance());

    catalystInstance.initialize();
    mDevSupportManager.onNewReactContextCreated(reactContext);
    mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
    moveReactContextToCurrentLifecycleState();

    for (ReactRootView rootView : mAttachedRootViews) {
      attachMeasuredRootViewToInstance(rootView, catalystInstance);
    }

    ReactInstanceEventListener[] listeners =
        new ReactInstanceEventListener[mReactInstanceEventListeners.size()];
    listeners = mReactInstanceEventListeners.toArray(listeners);

    for (ReactInstanceEventListener listener : listeners) {
      listener.onReactContextInitialized(reactContext);
    }
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  }
  @Override
  public void destroy() {
    UiThreadUtil.assertOnUiThread();

    if (mUseDeveloperSupport) {
      mDevSupportManager.setDevSupportEnabled(false);
    }

    moveToBeforeCreateLifecycleState();

    if (mReactContextInitAsyncTask != null) {
      mReactContextInitAsyncTask.cancel(true);
    }

    mMemoryPressureRouter.destroy(mApplicationContext);

    if (mCurrentReactContext != null) {
      mCurrentReactContext.destroy();
      mCurrentReactContext = null;
      mHasStartedCreatingInitialContext = false;
    }
    mCurrentActivity = null;

    ResourceDrawableIdHelper.getInstance().clear();
  }
 /**
  * Detach given {@param rootView} from current catalyst instance. It's safe to call this method
  * multiple times on the same {@param rootView} - in that case view will be detached with the
  * first call.
  */
 @Override
 public void detachRootView(ReactRootView rootView) {
   UiThreadUtil.assertOnUiThread();
   if (mAttachedRootViews.remove(rootView)) {
     if (mCurrentReactContext != null && mCurrentReactContext.hasActiveCatalystInstance()) {
       detachViewFromInstance(rootView, mCurrentReactContext.getCatalystInstance());
     }
   }
 }
  /**
   * Attach given {@param rootView} to a catalyst instance manager and start JS application using JS
   * module provided by {@link ReactRootView#getJSModuleName}. If the react context is currently
   * being (re)-created, or if react context has not been created yet, the JS application associated
   * with the provided root view will be started asynchronously, i.e this method won't block. This
   * view will then be tracked by this manager and in case of catalyst instance restart it will be
   * re-attached.
   */
  @Override
  public void attachMeasuredRootView(ReactRootView rootView) {
    UiThreadUtil.assertOnUiThread();
    mAttachedRootViews.add(rootView);

    // If react context is being created in the background, JS application will be started
    // automatically when creation completes, as root view is part of the attached root view list.
    if (mReactContextInitAsyncTask == null && mCurrentReactContext != null) {
      attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
    }
  }
  @Override
  public void onHostDestroy() {
    UiThreadUtil.assertOnUiThread();

    if (mUseDeveloperSupport) {
      mDevSupportManager.setDevSupportEnabled(false);
    }

    moveToBeforeCreateLifecycleState();
    mCurrentActivity = null;
  }
 private void tearDownReactContext(ReactContext reactContext) {
   UiThreadUtil.assertOnUiThread();
   if (mLifecycleState == LifecycleState.RESUMED) {
     reactContext.onHostPause();
   }
   for (ReactRootView rootView : mAttachedRootViews) {
     detachViewFromInstance(rootView, reactContext.getCatalystInstance());
   }
   reactContext.destroy();
   mDevSupportManager.onReactInstanceDestroyed(reactContext);
   mMemoryPressureRouter.removeMemoryPressureListener(reactContext.getCatalystInstance());
 }
  /**
   * Use this method when the activity resumes to enable invoking the back button directly from JS.
   *
   * <p>This method retains an instance to provided mDefaultBackButtonImpl. Thus it's important to
   * pass from the activity instance that owns this particular instance of {@link
   * XReactInstanceManagerImpl}, so that once this instance receive {@link #onHostDestroy} event it
   * will clear the reference to that defaultBackButtonImpl.
   *
   * @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
   *     this instance of {@link XReactInstanceManagerImpl}.
   */
  @Override
  public void onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
    UiThreadUtil.assertOnUiThread();

    mDefaultBackButtonImpl = defaultBackButtonImpl;
    if (mUseDeveloperSupport) {
      mDevSupportManager.setDevSupportEnabled(true);
    }

    mCurrentActivity = activity;
    moveToResumedLifecycleState(false);
  }
  @Override
  public void onHostPause() {
    UiThreadUtil.assertOnUiThread();

    mDefaultBackButtonImpl = null;
    if (mUseDeveloperSupport) {
      mDevSupportManager.setDevSupportEnabled(false);
    }

    moveToBeforeResumeLifecycleState();
    mCurrentActivity = null;
  }
 /**
  * This method will give JS the opportunity to consume the back button event. If JS does not
  * consume the event, mDefaultBackButtonImpl will be invoked at the end of the round trip to JS.
  */
 @Override
 public void onBackPressed() {
   UiThreadUtil.assertOnUiThread();
   ReactContext reactContext = mCurrentReactContext;
   if (mCurrentReactContext == null) {
     // Invoke without round trip to JS.
     FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
     invokeDefaultOnBackPressed();
   } else {
     DeviceEventManagerModule deviceEventManagerModule =
         Assertions.assertNotNull(reactContext).getNativeModule(DeviceEventManagerModule.class);
     deviceEventManagerModule.emitHardwareBackPressed();
   }
 }
  private void recreateReactContextInBackground(
      JavaScriptExecutor.Factory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
    UiThreadUtil.assertOnUiThread();

    ReactContextInitParams initParams =
        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
    if (mReactContextInitAsyncTask == null) {
      // No background task to create react context is currently running, create and execute one.
      mReactContextInitAsyncTask = new ReactContextInitAsyncTask();
      mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, initParams);
    } else {
      // Background task is currently running, queue up most recent init params to recreate context
      // once task completes.
      mPendingReactContextInitParams = initParams;
    }
  }
  private void attachMeasuredRootViewToInstance(
      ReactRootView rootView, CatalystInstance catalystInstance) {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachMeasuredRootViewToInstance");
    UiThreadUtil.assertOnUiThread();

    // Reset view content as it's going to be populated by the application content from JS
    rootView.removeAllViews();
    rootView.setId(View.NO_ID);

    UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
    int rootTag = uiManagerModule.addMeasuredRootView(rootView);
    @Nullable Bundle launchOptions = rootView.getLaunchOptions();
    WritableMap initialProps = Arguments.makeNativeMap(launchOptions);
    String jsAppModuleName = rootView.getJSModuleName();

    WritableNativeMap appParams = new WritableNativeMap();
    appParams.putDouble("rootTag", rootTag);
    appParams.putMap("initialProps", initialProps);
    catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  }
  private void recreateReactContextInBackgroundInner() {
    UiThreadUtil.assertOnUiThread();

    if (mUseDeveloperSupport && mJSMainModuleName != null) {
      final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();

      // If remote JS debugging is enabled, load from dev server.
      if (mDevSupportManager.hasUpToDateJSBundleInCache()
          && !devSettings.isRemoteJSDebugEnabled()) {
        // If there is a up-to-date bundle downloaded from server,
        // with remote JS debugging disabled, always use that.
        onJSBundleLoadedFromServer();
      } else if (mBundleLoader == null) {
        mDevSupportManager.handleReloadJS();
      } else {
        mDevSupportManager.isPackagerRunning(
            new DevServerHelper.PackagerStatusCallback() {
              @Override
              public void onPackagerStatusFetched(final boolean packagerIsRunning) {
                UiThreadUtil.runOnUiThread(
                    new Runnable() {
                      @Override
                      public void run() {
                        if (packagerIsRunning) {
                          mDevSupportManager.handleReloadJS();
                        } else {
                          // If dev server is down, disable the remote JS debugging.
                          devSettings.setRemoteJSDebugEnabled(false);
                          recreateReactContextInBackgroundFromBundleLoader();
                        }
                      }
                    });
              }
            });
      }
      return;
    }

    recreateReactContextInBackgroundFromBundleLoader();
  }
 private void detachViewFromInstance(ReactRootView rootView, CatalystInstance catalystInstance) {
   UiThreadUtil.assertOnUiThread();
   catalystInstance
       .getJSModule(AppRegistry.class)
       .unmountApplicationComponentAtRootTag(rootView.getId());
 }
 @Override
 public void showDevOptionsDialog() {
   UiThreadUtil.assertOnUiThread();
   mDevSupportManager.showDevOptionsDialog();
 }
 private void invokeDefaultOnBackPressed() {
   UiThreadUtil.assertOnUiThread();
   if (mDefaultBackButtonImpl != null) {
     mDefaultBackButtonImpl.invokeDefaultOnBackPressed();
   }
 }