コード例 #1
0
 @Override
 public void setRemoveClippedSubviews(boolean removeClippedSubviews) {
   if (removeClippedSubviews == mRemoveClippedSubviews) {
     return;
   }
   mRemoveClippedSubviews = removeClippedSubviews;
   if (removeClippedSubviews) {
     mClippingRect = new Rect();
     ReactClippingViewGroupHelper.calculateClippingRect(this, mClippingRect);
     mAllChildrenCount = getChildCount();
     int initialSize = Math.max(12, mAllChildrenCount);
     mAllChildren = new View[initialSize];
     mChildrenLayoutChangeListener = new ChildrenLayoutChangeListener(this);
     for (int i = 0; i < mAllChildrenCount; i++) {
       View child = getChildAt(i);
       mAllChildren[i] = child;
       child.addOnLayoutChangeListener(mChildrenLayoutChangeListener);
     }
     updateClippingRect();
   } else {
     // Add all clipped views back, deallocate additional arrays, remove layoutChangeListener
     Assertions.assertNotNull(mClippingRect);
     Assertions.assertNotNull(mAllChildren);
     Assertions.assertNotNull(mChildrenLayoutChangeListener);
     for (int i = 0; i < mAllChildrenCount; i++) {
       mAllChildren[i].removeOnLayoutChangeListener(mChildrenLayoutChangeListener);
     }
     getDrawingRect(mClippingRect);
     updateClippingToRect(mClippingRect);
     mAllChildren = null;
     mClippingRect = null;
     mAllChildrenCount = 0;
     mChildrenLayoutChangeListener = null;
   }
 }
コード例 #2
0
  private void updateSubviewClipStatus(View subview) {
    if (!mRemoveClippedSubviews || getParent() == null) {
      return;
    }

    Assertions.assertNotNull(mClippingRect);
    Assertions.assertNotNull(mAllChildren);

    // do fast check whether intersect state changed
    sHelperRect.set(subview.getLeft(), subview.getTop(), subview.getRight(), subview.getBottom());
    boolean intersects =
        mClippingRect.intersects(
            sHelperRect.left, sHelperRect.top, sHelperRect.right, sHelperRect.bottom);

    // If it was intersecting before, should be attached to the parent
    boolean oldIntersects = (subview.getParent() != null);

    if (intersects != oldIntersects) {
      int clippedSoFar = 0;
      for (int i = 0; i < mAllChildrenCount; i++) {
        if (mAllChildren[i] == subview) {
          updateSubviewClipStatus(mClippingRect, i, clippedSoFar);
          break;
        }
        if (mAllChildren[i].getParent() == null) {
          clippedSoFar++;
        }
      }
    }
  }
コード例 #3
0
  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);
  }
コード例 #4
0
    /**
     * Instantiates a new {@link ReactInstanceManagerImpl}. Before calling {@code build}, the
     * following must be called:
     *
     * <ul>
     *   <li>{@link #setApplication}
     *   <li>{@link #setJSBundleFile} or {@link #setJSMainModuleName}
     * </ul>
     */
    public ReactInstanceManager build() {
      Assertions.assertCondition(
          mUseDeveloperSupport || mJSBundleFile != null,
          "JS Bundle File has to be provided when dev support is disabled");

      Assertions.assertCondition(
          mJSMainModuleName != null || mJSBundleFile != null,
          "Either MainModuleName or JS Bundle File needs to be provided");

      if (mUIImplementationProvider == null) {
        // create default UIImplementationProvider if the provided one is null.
        mUIImplementationProvider = new UIImplementationProvider();
      }

      return new ReactInstanceManagerImpl(
          Assertions.assertNotNull(
              mApplication, "Application property has not been set with this builder"),
          mJSBundleFile,
          mJSMainModuleName,
          mPackages,
          mUseDeveloperSupport,
          mBridgeIdleDebugListener,
          Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
          mUIImplementationProvider,
          mNativeModuleCallExceptionHandler,
          mJSCConfig);
    }
コード例 #5
0
 @Override
 public void dispatch(RCTEventEmitter rctEventEmitter) {
   TouchesHelper.sendTouchEvent(
       rctEventEmitter,
       Assertions.assertNotNull(mTouchEventType),
       getViewTag(),
       Assertions.assertNotNull(mMotionEvent));
 }
コード例 #6
0
  @Override
  public void updateClippingRect() {
    if (!mRemoveClippedSubviews) {
      return;
    }

    Assertions.assertNotNull(mClippingRect);
    Assertions.assertNotNull(mAllChildren);

    ReactClippingViewGroupHelper.calculateClippingRect(this, mClippingRect);
    updateClippingToRect(mClippingRect);
  }
コード例 #7
0
 /*package*/ void addViewWithSubviewClippingEnabled(View child, int index, LayoutParams params) {
   Assertions.assertCondition(mRemoveClippedSubviews);
   Assertions.assertNotNull(mClippingRect);
   Assertions.assertNotNull(mAllChildren);
   addInArray(child, index);
   // we add view as "clipped" and then run {@link #updateSubviewClipStatus} to conditionally
   // attach it
   int clippedSoFar = 0;
   for (int i = 0; i < index; i++) {
     if (mAllChildren[i].getParent() == null) {
       clippedSoFar++;
     }
   }
   updateSubviewClipStatus(mClippingRect, index, clippedSoFar);
   child.addOnLayoutChangeListener(mChildrenLayoutChangeListener);
 }
コード例 #8
0
  /**
   * Destroys this catalyst instance, waiting for any other threads in CatalystQueueConfiguration
   * (besides the UI thread) to finish running. Must be called from the UI thread so that we can
   * fully shut down other threads.
   */
  /* package */ void destroy() {
    UiThreadUtil.assertOnUiThread();

    if (mDestroyed) {
      return;
    }

    // TODO: tell all APIs to shut down
    mDestroyed = true;
    mJavaRegistry.notifyCatalystInstanceDestroy();
    mCatalystQueueConfiguration.destroy();
    boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
    if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
      for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
        listener.onTransitionToBridgeIdle();
      }
    }

    if (mTraceListener != null) {
      Systrace.unregisterListener(mTraceListener);
    }

    // We can access the Bridge from any thread now because we know either we are on the JS thread
    // or the JS thread has finished via CatalystQueueConfiguration#destroy()
    Assertions.assertNotNull(mBridge).dispose();
  }
コード例 #9
0
 @Override
 public void run() {
   Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "DispatchEventsRunnable");
   try {
     Systrace.endAsyncFlow(
         Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
         "ScheduleDispatchFrameCallback",
         mHasDispatchScheduledCount);
     mHasDispatchScheduled = false;
     mHasDispatchScheduledCount++;
     Assertions.assertNotNull(mRCTEventEmitter);
     synchronized (mEventsToDispatchLock) {
       // We avoid allocating an array and iterator, and "sorting" if we don't need to.
       // This occurs when the size of mEventsToDispatch is zero or one.
       if (mEventsToDispatchSize > 1) {
         Arrays.sort(mEventsToDispatch, 0, mEventsToDispatchSize, EVENT_COMPARATOR);
       }
       for (int eventIdx = 0; eventIdx < mEventsToDispatchSize; eventIdx++) {
         Event event = mEventsToDispatch[eventIdx];
         // Event can be null if it has been coalesced into another event.
         if (event == null) {
           continue;
         }
         Systrace.endAsyncFlow(
             Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, event.getEventName(), event.getUniqueID());
         event.dispatch(mRCTEventEmitter);
         event.dispose();
       }
       clearEventsToDispatch();
       mEventCookieToLastEventIdx.clear();
     }
   } finally {
     Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
   }
 }
コード例 #10
0
 private void addInArray(View child, int index) {
   View[] children = Assertions.assertNotNull(mAllChildren);
   final int count = mAllChildrenCount;
   final int size = children.length;
   if (index == count) {
     if (size == count) {
       mAllChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
       System.arraycopy(children, 0, mAllChildren, 0, size);
       children = mAllChildren;
     }
     children[mAllChildrenCount++] = child;
   } else if (index < count) {
     if (size == count) {
       mAllChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
       System.arraycopy(children, 0, mAllChildren, 0, index);
       System.arraycopy(children, index, mAllChildren, index + 1, count - index);
       children = mAllChildren;
     } else {
       System.arraycopy(children, index, children, index + 1, count - index);
     }
     children[index] = child;
     mAllChildrenCount++;
   } else {
     throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
   }
 }
コード例 #11
0
  private void enqueueOnChangeEndpointLongPolling() {
    Request request = new Request.Builder().url(createOnChangeEndpointUrl()).tag(this).build();
    Assertions.assertNotNull(mOnChangePollingClient)
        .newCall(request)
        .enqueue(
            new Callback() {
              @Override
              public void onFailure(Request request, IOException e) {
                if (mOnChangePollingEnabled) {
                  // this runnable is used by onchange endpoint poller to delay subsequent requests
                  // in case
                  // of a failure, so that we don't flood network queue with frequent requests in
                  // case when
                  // dev server is down
                  FLog.d(ReactConstants.TAG, "Error while requesting /onchange endpoint", e);
                  mRestartOnChangePollingHandler.postDelayed(
                      new Runnable() {
                        @Override
                        public void run() {
                          handleOnChangePollingResponse(false);
                        }
                      },
                      LONG_POLL_FAILURE_DELAY_MS);
                }
              }

              @Override
              public void onResponse(Response response) throws IOException {
                handleOnChangePollingResponse(response.code() == 205);
              }
            });
  }
コード例 #12
0
 @Override
 public void onTraceStopped() {
   getJSModule(
           Assertions.assertNotNull(mMainExecutorToken),
           com.facebook.react.bridge.Systrace.class)
       .setEnabled(false);
 }
コード例 #13
0
 /*package*/ void removeViewWithSubviewClippingEnabled(View view) {
   Assertions.assertCondition(mRemoveClippedSubviews);
   Assertions.assertNotNull(mClippingRect);
   Assertions.assertNotNull(mAllChildren);
   view.removeOnLayoutChangeListener(mChildrenLayoutChangeListener);
   int index = indexOfChildInAllChildren(view);
   if (mAllChildren[index].getParent() != null) {
     int clippedSoFar = 0;
     for (int i = 0; i < index; i++) {
       if (mAllChildren[i].getParent() == null) {
         clippedSoFar++;
       }
     }
     super.removeViewsInLayout(index - clippedSoFar, 1);
   }
   removeFromArray(index);
 }
コード例 #14
0
    public T get() throws Exception {
      if (mException != null) {
        throw mException;
      }

      Assertions.assertNotNull(mResult);

      return mResult;
    }
コード例 #15
0
 /*package*/ void removeAllViewsWithSubviewClippingEnabled() {
   Assertions.assertCondition(mRemoveClippedSubviews);
   Assertions.assertNotNull(mAllChildren);
   for (int i = 0; i < mAllChildrenCount; i++) {
     mAllChildren[i].removeOnLayoutChangeListener(mChildrenLayoutChangeListener);
   }
   removeAllViewsInLayout();
   mAllChildrenCount = 0;
 }
コード例 #16
0
  public void loadApp(
      String appKey,
      ReactInstanceSpecForTest spec,
      @Nullable Bundle initialProps,
      String bundleName,
      boolean useDevSupport) {

    final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1);
    mBridgeIdleSignaler = new ReactBridgeIdleSignaler();

    ReactInstanceManager.Builder builder =
        ReactTestHelper.getReactTestFactory()
            .getReactInstanceManagerBuilder()
            .setApplication(getApplication())
            .setBundleAssetName(bundleName)
            // By not setting a JS module name, we force the bundle to be always loaded from
            // assets, not the devserver, even if dev mode is enabled (such as when testing
            // redboxes).
            // This makes sense because we never run the devserver in tests.
            // .setJSMainModuleName()
            .addPackage(
                spec.getAlternativeReactPackageForTest() != null
                    ? spec.getAlternativeReactPackageForTest()
                    : new MainReactPackage())
            .addPackage(new InstanceSpecForTestPackage(spec))
            .setUseDeveloperSupport(useDevSupport)
            .setBridgeIdleDebugListener(mBridgeIdleSignaler)
            .setInitialLifecycleState(mLifecycleState);

    mReactInstanceManager = builder.build();
    mReactInstanceManager.onResume(this, this);

    Assertions.assertNotNull(mReactRootView)
        .getViewTreeObserver()
        .addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
              @Override
              public void onGlobalLayout() {
                currentLayoutEvent.countDown();
              }
            });
    Assertions.assertNotNull(mReactRootView)
        .startReactApplication(mReactInstanceManager, appKey, initialProps);
  }
コード例 #17
0
 private void updateClippingToRect(Rect clippingRect) {
   Assertions.assertNotNull(mAllChildren);
   int clippedSoFar = 0;
   for (int i = 0; i < mAllChildrenCount; i++) {
     updateSubviewClipStatus(clippingRect, i, clippedSoFar);
     if (mAllChildren[i].getParent() == null) {
       clippedSoFar++;
     }
   }
 }
コード例 #18
0
 /**
  * @return Themed React context for view with a given {@param reactTag} - in the case of root view
  *     it returns the context from {@link #mRootViewsContext} and all the other cases it gets the
  *     context directly from the view using {@link View#getContext}.
  */
 private ThemedReactContext getReactContextForView(int reactTag) {
   if (mRootTags.get(reactTag)) {
     return Assertions.assertNotNull(mRootViewsContext.get(reactTag));
   }
   View view = mTagsToViews.get(reactTag);
   if (view == null) {
     throw new JSApplicationIllegalArgumentException("Could not find view with tag " + reactTag);
   }
   return (ThemedReactContext) view.getContext();
 }
コード例 #19
0
 private int indexOfChildInAllChildren(View child) {
   final int count = mAllChildrenCount;
   final View[] children = Assertions.assertNotNull(mAllChildren);
   for (int i = 0; i < count; i++) {
     if (children[i] == child) {
       return i;
     }
   }
   return -1;
 }
コード例 #20
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);
    }
  }
コード例 #21
0
 // This method also sets the child's mParent to null
 private void removeFromArray(int index) {
   final View[] children = Assertions.assertNotNull(mAllChildren);
   final int count = mAllChildrenCount;
   if (index == count - 1) {
     children[--mAllChildrenCount] = null;
   } else if (index >= 0 && index < count) {
     System.arraycopy(children, index + 1, children, index, count - index - 1);
     children[--mAllChildrenCount] = null;
   } else {
     throw new IndexOutOfBoundsException();
   }
 }
コード例 #22
0
  // This is called from java code, so it won't be stripped anyway, but proguard will rename it,
  // which this prevents.
  @DoNotStrip
  @Override
  public void invokeCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments) {
    synchronized (mTeardownLock) {
      if (mDestroyed) {
        FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
        return;
      }

      incrementPendingJSCalls();

      Assertions.assertNotNull(mBridge).invokeCallback(executorToken, callbackID, arguments);
    }
  }
コード例 #23
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();
   }
 }
コード例 #24
0
  /**
   * Handles an updateLayout call. All updateLayout calls are collected and dispatched at the end of
   * a batch because updateLayout calls to layout-only nodes can necessitate multiple updateLayout
   * calls for all its children.
   */
  public void handleUpdateLayout(ReactShadowNode node) {
    if (!ENABLED) {
      mUIViewOperationQueue.enqueueUpdateLayout(
          Assertions.assertNotNull(node.getParent()).getReactTag(),
          node.getReactTag(),
          node.getScreenX(),
          node.getScreenY(),
          node.getScreenWidth(),
          node.getScreenHeight());
      return;
    }

    applyLayoutBase(node);
  }
コード例 #25
0
 public CatalystInstance build() {
   return new CatalystInstance(
       Assertions.assertNotNull(mCatalystQueueConfigurationSpec),
       Assertions.assertNotNull(mJSExecutor),
       Assertions.assertNotNull(mRegistry),
       Assertions.assertNotNull(mJSModulesConfig),
       Assertions.assertNotNull(mJSBundleLoader),
       Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
 }
コード例 #26
0
  // Because react context is created asynchronously, we may have to wait until it is available.
  // It's simpler than exposing synchronosition mechanism to notify listener than react context
  // creation has completed.
  private ReactContext waitForReactContext() {
    Assertions.assertNotNull(mReactInstanceManager);

    try {
      while (true) {
        ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
        if (reactContext != null) {
          return reactContext;
        }
        Thread.sleep(100);
      }
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }
コード例 #27
0
 @Override
 public boolean canCoalesce() {
   // We can coalesce move events but not start/end events. Coalescing move events should probably
   // append historical move data like MotionEvent batching does. This is left as an exercise for
   // the reader.
   switch (Assertions.assertNotNull(mTouchEventType)) {
     case START:
     case END:
     case CANCEL:
       return false;
     case MOVE:
       return true;
     default:
       throw new RuntimeException("Unknown touch event type: " + mTouchEventType);
   }
 }
コード例 #28
0
  /* package */ void callFunction(
      ExecutorToken executorToken,
      int moduleId,
      int methodId,
      NativeArray arguments,
      String tracingName) {
    synchronized (mTeardownLock) {
      if (mDestroyed) {
        FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
        return;
      }

      incrementPendingJSCalls();

      Assertions.assertNotNull(mBridge)
          .callFunction(executorToken, moduleId, methodId, arguments, tracingName);
    }
  }
コード例 #29
0
  @Override
  public void onNewIntent(Intent intent) {
    if (mCurrentReactContext == null) {
      FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
    } else {
      String action = intent.getAction();
      Uri uri = intent.getData();

      if (Intent.ACTION_VIEW.equals(action) && uri != null) {
        DeviceEventManagerModule deviceEventManagerModule =
            Assertions.assertNotNull(mCurrentReactContext)
                .getNativeModule(DeviceEventManagerModule.class);
        deviceEventManagerModule.emitNewIntentReceived(uri);
      }

      mCurrentReactContext.onNewIntent(mCurrentActivity, intent);
    }
  }
コード例 #30
0
 private void assertNodeDoesNotNeedCustomLayoutForChildren(ReactShadowNode node) {
   ViewManager viewManager = Assertions.assertNotNull(mViewManagers.get(node.getViewClass()));
   ViewGroupManager viewGroupManager;
   if (viewManager instanceof ViewGroupManager) {
     viewGroupManager = (ViewGroupManager) viewManager;
   } else {
     throw new IllegalViewOperationException(
         "Trying to use view "
             + node.getViewClass()
             + " as a parent, but its Manager doesn't extends ViewGroupManager");
   }
   if (viewGroupManager != null && viewGroupManager.needsCustomLayoutForChildren()) {
     throw new IllegalViewOperationException(
         "Trying to measure a view using measureLayout/measureLayoutRelativeToParent relative to"
             + " an ancestor that requires custom layout for it's children ("
             + node.getViewClass()
             + "). Use measure instead.");
   }
 }