コード例 #1
0
  private void recreateReactContextInBackgroundInner() {
    UiThreadUtil.assertOnUiThread();

    if (mUseDeveloperSupport && mJSMainModuleName != null) {
      if (mDevSupportManager.hasUpToDateJSBundleInCache()) {
        // If there is a up-to-date bundle downloaded from server, always use that
        onJSBundleLoadedFromServer();
      } else if (mJSBundleFile == 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 {
                          recreateReactContextInBackgroundFromBundleFile();
                        }
                      }
                    });
              }
            });
      }
      return;
    }

    recreateReactContextInBackgroundFromBundleFile();
  }
コード例 #2
0
    @Override
    public void doFrame(long frameTimeNanos) {
      UiThreadUtil.assertOnUiThread();

      if (mShouldStop) {
        mIsPosted = false;
      } else {
        post();
      }

      Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ScheduleDispatchFrameCallback");
      try {
        moveStagedEventsToDispatchQueue();

        if (mEventsToDispatchSize > 0 && !mHasDispatchScheduled) {
          mHasDispatchScheduled = true;
          Systrace.startAsyncFlow(
              Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
              "ScheduleDispatchFrameCallback",
              mHasDispatchScheduledCount);
          mReactContext.runOnJSQueueThread(mDispatchEventsRunnable);
        }
      } finally {
        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
      }
    }
コード例 #3
0
 @Override
 public void onHostResume() {
   UiThreadUtil.assertOnUiThread();
   if (mRCTEventEmitter == null) {
     mRCTEventEmitter = mReactContext.getJSModule(RCTEventEmitter.class);
   }
   mCurrentFrameCallback.maybePost();
 }
コード例 #4
0
 /**
  * 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());
     }
   }
 }
コード例 #5
0
 public void removeRootView(int rootViewTag) {
   UiThreadUtil.assertOnUiThread();
   if (!mRootTags.get(rootViewTag)) {
     SoftAssertions.assertUnreachable(
         "View with tag " + rootViewTag + " is not registered as a root view");
   }
   View rootView = mTagsToViews.get(rootViewTag);
   dropView(rootView);
   mRootTags.delete(rootViewTag);
   mRootViewsContext.remove(rootViewTag);
 }
コード例 #6
0
  /**
   * 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());
    }
  }
コード例 #7
0
  /**
   * Returns true on success, false on failure. If successful, after calling, output buffer will be
   * {x, y, width, height}.
   */
  public void measure(int tag, int[] outputBuffer) {
    UiThreadUtil.assertOnUiThread();
    View v = mTagsToViews.get(tag);
    if (v == null) {
      throw new NoSuchNativeViewException("No native view for " + tag + " currently exists");
    }

    // Puts x/y in outputBuffer[0]/[1]
    v.getLocationOnScreen(outputBuffer);
    outputBuffer[2] = v.getWidth();
    outputBuffer[3] = v.getHeight();
  }
コード例 #8
0
 private void tearDownReactContext(ReactContext reactContext) {
   UiThreadUtil.assertOnUiThread();
   if (mLifecycleState == LifecycleState.RESUMED) {
     reactContext.onPause();
   }
   for (ReactRootView rootView : mAttachedRootViews) {
     detachViewFromInstance(rootView, reactContext.getCatalystInstance());
   }
   reactContext.onDestroy();
   mDevSupportManager.onReactInstanceDestroyed(reactContext);
   mMemoryPressureRouter.onReactInstanceDestroyed();
 }
コード例 #9
0
 /**
  * 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();
   }
 }
コード例 #10
0
  public void updateViewExtraData(int tag, Object extraData) {
    UiThreadUtil.assertOnUiThread();

    ViewManager viewManager = mTagsToViewManagers.get(tag);
    if (viewManager == null) {
      throw new IllegalViewOperationException("ViewManager for tag " + tag + " could not be found");
    }

    View viewToUpdate = mTagsToViews.get(tag);
    if (viewToUpdate == null) {
      throw new IllegalViewOperationException(
          "Trying to update view with tag " + tag + " which " + "doesn't exist");
    }
    viewManager.updateExtraData(viewToUpdate, extraData);
  }
コード例 #11
0
  public void updateProperties(int tag, CatalystStylesDiffMap props) {
    UiThreadUtil.assertOnUiThread();

    ViewManager viewManager = mTagsToViewManagers.get(tag);
    if (viewManager == null) {
      throw new IllegalViewOperationException("ViewManager for tag " + tag + " could not be found");
    }

    View viewToUpdate = mTagsToViews.get(tag);
    if (viewToUpdate == null) {
      throw new IllegalViewOperationException(
          "Trying to update view with tag " + tag + " which doesn't exist");
    }
    viewManager.updateProperties(viewToUpdate, props);
  }
コード例 #12
0
  /**
   * See {@link UIManagerModule#addMeasuredRootView}.
   *
   * <p>Must be called from the UI thread.
   */
  public void addRootView(
      int tag, SizeMonitoringFrameLayout view, ThemedReactContext themedContext) {
    UiThreadUtil.assertOnUiThread();
    if (view.getId() != View.NO_ID) {
      throw new IllegalViewOperationException(
          "Trying to add a root view with an explicit id already set. React Native uses "
              + "the id field to track react tags and will overwrite this field. If that is fine, "
              + "explicitly overwrite the id field to View.NO_ID before calling addMeasuredRootView.");
    }

    mTagsToViews.put(tag, view);
    mTagsToViewManagers.put(tag, mRootViewManager);
    mRootTags.put(tag, true);
    mRootViewsContext.put(tag, themedContext);
    view.setId(tag);
  }
コード例 #13
0
  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.execute(initParams);
    } else {
      // Background task is currently running, queue up most recent init params to recreate context
      // once task completes.
      mPendingReactContextInitParams = initParams;
    }
  }
コード例 #14
0
  public void dispatchCommand(int reactTag, int commandId, @Nullable ReadableArray args) {
    UiThreadUtil.assertOnUiThread();
    View view = mTagsToViews.get(reactTag);
    if (view == null) {
      throw new IllegalViewOperationException(
          "Trying to send command to a non-existing view " + "with tag " + reactTag);
    }

    ViewManager viewManager = mTagsToViewManagers.get(reactTag);
    if (viewManager == null) {
      throw new IllegalViewOperationException(
          "ViewManager for view tag " + reactTag + " could not be found");
    }

    viewManager.receiveCommand(view, commandId, args);
  }
コード例 #15
0
  @Override
  public void onPause() {
    UiThreadUtil.assertOnUiThread();

    mLifecycleState = LifecycleState.BEFORE_RESUME;

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

    mCurrentActivity = null;
    if (mCurrentReactContext != null) {
      mCurrentReactContext.onPause();
    }
  }
コード例 #16
0
  /**
   * 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
   * ReactInstanceManagerImpl}, so that once this instance receive {@link #onDestroy} event it will
   * clear the reference to that defaultBackButtonImpl.
   *
   * @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
   *     this instance of {@link ReactInstanceManagerImpl}.
   */
  @Override
  public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
    UiThreadUtil.assertOnUiThread();

    mLifecycleState = LifecycleState.RESUMED;

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

    mCurrentActivity = activity;
    if (mCurrentReactContext != null) {
      mCurrentReactContext.onResume(activity);
    }
  }
コード例 #17
0
  public void updateLayout(int parentTag, int tag, int x, int y, int width, int height) {
    UiThreadUtil.assertOnUiThread();

    View viewToUpdate = mTagsToViews.get(tag);
    if (viewToUpdate == null) {
      throw new IllegalViewOperationException(
          "Trying to update view with tag " + tag + " which " + "doesn't exist");
    }

    // Even though we have exact dimensions, we still call measure because some platform views (e.g.
    // Switch) assume that method will always be called before onLayout and onDraw. They use it to
    // calculate and cache information used in the draw pass. For most views, onMeasure can be
    // stubbed out to only call setMeasuredDimensions. For ViewGroups, onLayout should be stubbed
    // out to not recursively call layout on its children: React Native already handles doing that.
    //
    // Also, note measure and layout need to be called *after* all View properties have been updated
    // because of caching and calculation that may occur in onMeasure and onLayout. Layout
    // operations should also follow the native view hierarchy and go top to bottom for consistency
    // with standard layout passes (some views may depend on this).

    viewToUpdate.measure(
        View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
        View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));

    // Check if the parent of the view has to layout the view, or the child has to lay itself out.
    if (!mRootTags.get(parentTag)) {
      ViewManager parentViewManager = mTagsToViewManagers.get(parentTag);
      ViewGroupManager parentViewGroupManager;
      if (parentViewManager instanceof ViewGroupManager) {
        parentViewGroupManager = (ViewGroupManager) parentViewManager;
      } else {
        throw new IllegalViewOperationException(
            "Trying to use view with tag "
                + tag
                + " as a parent, but its Manager doesn't extends ViewGroupManager");
      }
      if (parentViewGroupManager != null
          && !parentViewGroupManager.needsCustomLayoutForChildren()) {
        viewToUpdate.layout(x, y, x + width, y + height);
      }
    } else {
      viewToUpdate.layout(x, y, x + width, y + height);
    }
  }
コード例 #18
0
  /**
   * Show a {@link PopupMenu}.
   *
   * @param reactTag the tag of the anchor view (the PopupMenu is displayed next to this view); this
   *     needs to be the tag of a native view (shadow views can not be anchors)
   * @param items the menu items as an array of strings
   * @param success will be called with the position of the selected item as the first argument, or
   *     no arguments if the menu is dismissed
   */
  public void showPopupMenu(int reactTag, ReadableArray items, Callback success) {
    UiThreadUtil.assertOnUiThread();
    View anchor = mTagsToViews.get(reactTag);
    if (anchor == null) {
      throw new JSApplicationIllegalArgumentException("Could not find view with tag " + reactTag);
    }
    PopupMenu popupMenu = new PopupMenu(getReactContextForView(reactTag), anchor);

    Menu menu = popupMenu.getMenu();
    for (int i = 0; i < items.size(); i++) {
      menu.add(Menu.NONE, Menu.NONE, i, items.getString(i));
    }

    PopupMenuCallbackHandler handler = new PopupMenuCallbackHandler(success);
    popupMenu.setOnMenuItemClickListener(handler);
    popupMenu.setOnDismissListener(handler);

    popupMenu.show();
  }
コード例 #19
0
  private void setupReactContext(ReactApplicationContext reactContext) {
    UiThreadUtil.assertOnUiThread();
    Assertions.assertCondition(mCurrentReactContext == null);
    mCurrentReactContext = Assertions.assertNotNull(reactContext);
    CatalystInstance catalystInstance =
        Assertions.assertNotNull(reactContext.getCatalystInstance());

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

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

    for (ReactInstanceEventListener listener : mReactInstanceEventListeners) {
      listener.onReactContextInitialized(reactContext);
    }
  }
コード例 #20
0
  private void attachMeasuredRootViewToInstance(
      ReactRootView rootView, CatalystInstance catalystInstance) {
    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 =
        launchOptions != null ? Arguments.fromBundle(launchOptions) : Arguments.createMap();
    String jsAppModuleName = rootView.getJSModuleName();

    WritableNativeMap appParams = new WritableNativeMap();
    appParams.putDouble("rootTag", rootTag);
    appParams.putMap("initialProps", initialProps);
    catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
  }
コード例 #21
0
  @Override
  public void onDestroy() {
    UiThreadUtil.assertOnUiThread();

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

    mMemoryPressureRouter.destroy(mApplicationContext);
    if (mUseDeveloperSupport) {
      mDevSupportManager.setDevSupportEnabled(false);
    }

    if (mCurrentReactContext != null) {
      mCurrentReactContext.onDestroy();
      mCurrentReactContext = null;
      mHasStartedCreatingInitialContext = false;
    }
    mCurrentActivity = null;
  }
コード例 #22
0
  public void createView(
      int rootViewTagForContext,
      int tag,
      String className,
      @Nullable CatalystStylesDiffMap initialProps) {
    UiThreadUtil.assertOnUiThread();
    ViewManager viewManager = mViewManagers.get(className);

    View view =
        viewManager.createView(mRootViewsContext.get(rootViewTagForContext), mJSResponderHandler);
    mTagsToViews.put(tag, view);
    mTagsToViewManagers.put(tag, viewManager);

    // Use android View id field to store React tag. This is possible since we don't inflate
    // React views from layout xmls. Thus it is easier to just reuse that field instead of
    // creating another (potentially much more expensive) mapping from view to React tag
    view.setId(tag);
    if (initialProps != null) {
      viewManager.updateProperties(view, initialProps);
    }
  }
コード例 #23
0
 /** Releases all references to given native View. */
 private void dropView(View view) {
   UiThreadUtil.assertOnUiThread();
   if (!mRootTags.get(view.getId())) {
     // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}
     Assertions.assertNotNull(mTagsToViewManagers.get(view.getId()))
         .onDropViewInstance((ThemedReactContext) view.getContext(), view);
   }
   ViewManager viewManager = mTagsToViewManagers.get(view.getId());
   if (view instanceof ViewGroup && viewManager instanceof ViewGroupManager) {
     ViewGroup viewGroup = (ViewGroup) view;
     ViewGroupManager viewGroupManager = (ViewGroupManager) viewManager;
     for (int i = viewGroupManager.getChildCount(viewGroup) - 1; i >= 0; i--) {
       View child = viewGroupManager.getChildAt(viewGroup, i);
       if (mTagsToViews.get(child.getId()) != null) {
         dropView(child);
       }
     }
     viewGroupManager.removeAllViews(viewGroup);
   }
   mTagsToViews.remove(view.getId());
   mTagsToViewManagers.remove(view.getId());
 }
コード例 #24
0
  /* package */ void startAnimationForNativeView(
      int reactTag, Animation animation, @Nullable final Callback animationCallback) {
    UiThreadUtil.assertOnUiThread();
    View view = mTagsToViews.get(reactTag);
    final int animationId = animation.getAnimationID();
    if (view != null) {
      animation.setAnimationListener(
          new AnimationListener() {
            @Override
            public void onFinished() {
              Animation removedAnimation = mAnimationRegistry.removeAnimation(animationId);

              // There's a chance that there was already a removeAnimation call enqueued on the main
              // thread when this callback got enqueued on the main thread, but the Animation class
              // should handle only calling one of onFinished and onCancel exactly once.
              Assertions.assertNotNull(removedAnimation, "Animation was already removed somehow!");
              if (animationCallback != null) {
                animationCallback.invoke(true);
              }
            }

            @Override
            public void onCancel() {
              Animation removedAnimation = mAnimationRegistry.removeAnimation(animationId);

              Assertions.assertNotNull(removedAnimation, "Animation was already removed somehow!");
              if (animationCallback != null) {
                animationCallback.invoke(false);
              }
            }
          });
      animation.start(view);
    } else {
      // TODO(5712813): cleanup callback in JS callbacks table in case of an error
      throw new IllegalViewOperationException("View with tag " + reactTag + " not found");
    }
  }
コード例 #25
0
 private void detachViewFromInstance(ReactRootView rootView, CatalystInstance catalystInstance) {
   UiThreadUtil.assertOnUiThread();
   catalystInstance
       .getJSModule(AppRegistry.class)
       .unmountApplicationComponentAtRootTag(rootView.getId());
 }
コード例 #26
0
 private void stopFrameCallback() {
   UiThreadUtil.assertOnUiThread();
   mCurrentFrameCallback.stop();
 }
コード例 #27
0
 @Override
 public void showDevOptionsDialog() {
   UiThreadUtil.assertOnUiThread();
   mDevSupportManager.showDevOptionsDialog();
 }
コード例 #28
0
 private void invokeDefaultOnBackPressed() {
   UiThreadUtil.assertOnUiThread();
   if (mDefaultBackButtonImpl != null) {
     mDefaultBackButtonImpl.invokeDefaultOnBackPressed();
   }
 }