@Override public void onExecutorDestroyed(ExecutorToken executorToken) { synchronized (mTimerGuard) { SparseArray<Timer> timersForContext = mTimerIdsToTimers.remove(executorToken); if (timersForContext == null) { return; } for (int i = 0; i < timersForContext.size(); i++) { Timer timer = timersForContext.get(timersForContext.keyAt(i)); mTimers.remove(timer); } } synchronized (mIdleCallbackGuard) { mSendIdleEventsExecutorTokens.remove(executorToken); } }
@ReactMethod public void deleteTimer(ExecutorToken executorToken, int timerId) { synchronized (mTimerGuard) { SparseArray<Timer> timersForContext = mTimerIdsToTimers.get(executorToken); if (timersForContext == null) { return; } Timer timer = timersForContext.get(timerId); if (timer == null) { return; } // We may have already called/removed it timersForContext.remove(timerId); if (timersForContext.size() == 0) { mTimerIdsToTimers.remove(executorToken); } mTimers.remove(timer); } }
@ReactMethod public void setSendIdleEvents(ExecutorToken executorToken, boolean sendIdleEvents) { synchronized (mIdleCallbackGuard) { if (sendIdleEvents) { mSendIdleEventsExecutorTokens.add(executorToken); } else { mSendIdleEventsExecutorTokens.remove(executorToken); } } UiThreadUtil.runOnUiThread(new Runnable() { @Override public void run() { synchronized (mIdleCallbackGuard) { if (mSendIdleEventsExecutorTokens.size() > 0) { setChoreographerIdleCallback(); } else { clearChoreographerIdleCallback(); } } } }); }
@Override public void callFunction( ExecutorToken executorToken, final String module, final String method, final NativeArray arguments) { if (mDestroyed) { FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed."); return; } if (!mAcceptCalls) { // Most of the time the instance is initialized and we don't need to acquire the lock synchronized (mJSCallsPendingInitLock) { if (!mAcceptCalls) { mJSCallsPendingInit.add(new PendingJSCall(executorToken, module, method, arguments)); return; } } } jniCallJSFunction(executorToken, module, method, arguments); }
@Test public void testFailGetWithInvalidHeadersStruct() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); List<JavaOnlyArray> invalidHeaders = Arrays.asList(JavaOnlyArray.of("foo")); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http://somedoman/foo", 0, JavaOnlyArray.from(invalidHeaders), null, true, 0); verifyErrorEmit(emitter, 0); }
@Test public void testFailPostWithoutContentType() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); JavaOnlyMap body = new JavaOnlyMap(); body.putString("string", "This is request body"); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http://somedomain/bar", 0, JavaOnlyArray.of(), body, true, 0); verifyErrorEmit(emitter, 0); }
@ReactMethod public void deleteTimer(ExecutorToken executorToken, int timerId) { synchronized (mTimerGuard) { SparseArray<Timer> timersForContext = mTimerIdsToTimers.get(executorToken); if (timersForContext == null) { return; } Timer timer = timersForContext.get(timerId); if (timer == null) { return; } // We may have already called/removed it mTimerIdsToTimers.remove(timerId); mTimers.remove(timer); } }
@Override public void callFunction( ExecutorToken executorToken, final String module, final String method, final NativeArray arguments) { if (mDestroyed) { FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed."); return; } if (!mAcceptCalls) { throw new RuntimeException("Attempt to call JS function before JS bundle is loaded."); } callJSFunction(executorToken, module, method, arguments); }
private Timer( ExecutorToken executorToken, int callbackID, long initialTargetTime, int duration, boolean repeat) { mExecutorToken = executorToken; mCallbackID = callbackID; mTargetTime = initialTargetTime; mInterval = duration; mRepeat = repeat; }
@Override public void run() { if (mCancelled) { return; } long frameTimeMillis = mFrameStartTime / 1000000; long timeSinceBoot = SystemClock.uptimeMillis(); long frameTimeElapsed = timeSinceBoot - frameTimeMillis; long time = SystemClock.currentTimeMillis(); long absoluteFrameStartTime = time - frameTimeElapsed; if (FRAME_DURATION_MS - (float) frameTimeElapsed < IDLE_CALLBACK_FRAME_DEADLINE_MS) { return; } mIdleCallbackContextsToCall.clear(); synchronized (mIdleCallbackGuard) { mIdleCallbackContextsToCall.addAll(mSendIdleEventsExecutorTokens); } for (ExecutorToken context : mIdleCallbackContextsToCall) { getReactApplicationContext().getJSModule(context, JSTimersExecution.class) .callIdleCallbacks(absoluteFrameStartTime); } mCurrentIdleCallbackRunnable = null; }
public PendingJSCall( ExecutorToken executorToken, String module, String method, NativeArray arguments) { mExecutorToken = executorToken; mModule = module; mMethod = method; mArguments = arguments; }
@Override public void invokeCallback(ExecutorToken executorToken, final int callbackID, final NativeArray arguments) { if (mDestroyed) { FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed."); return; } jniCallJSCallback(executorToken, callbackID, arguments); }
@DoNotStrip public void invoke(ExecutorToken token, int methodId, ReadableNativeArray parameters) { if (mMethods == null || methodId >= mMethods.size()) { return; } mMethods.get(methodId).invoke(mJSInstance, token, parameters); }
@Test public void testGetWithoutHeaders() throws Exception { OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http://somedomain/foo", /* requestId */ 0, /* headers */ JavaOnlyArray.of(), /* body */ null, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0, /* withCredentials */ false); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); assertThat(argumentCaptor.getValue().url().toString()).isEqualTo("http://somedomain/foo"); // We set the User-Agent header by default assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(1); assertThat(argumentCaptor.getValue().method()).isEqualTo("GET"); }
@Test public void testFailGetWithInvalidHeadersStruct() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); List<JavaOnlyArray> invalidHeaders = Arrays.asList(JavaOnlyArray.of("foo")); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http://somedoman/foo", /* requestId */ 0, /* headers */ JavaOnlyArray.from(invalidHeaders), /* body */ null, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0, /* withCredentials */ false); verifyErrorEmit(emitter, 0); }
@Test public void testFailPostWithoutContentType() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); JavaOnlyMap body = new JavaOnlyMap(); body.putString("string", "This is request body"); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http://somedomain/bar", 0, JavaOnlyArray.of(), body, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0, /* withCredentials */ false); verifyErrorEmit(emitter, 0); }
@Test public void testHeaders() throws Exception { OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient); List<JavaOnlyArray> headers = Arrays.asList( JavaOnlyArray.of("Accept", "text/plain"), JavaOnlyArray.of("User-Agent", "React test agent/1.0")); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http://someurl/baz", 0, JavaOnlyArray.from(headers), null, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0, /* withCredentials */ false); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); Headers requestHeaders = argumentCaptor.getValue().headers(); assertThat(requestHeaders.size()).isEqualTo(2); assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain"); assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0"); }
@Test public void testGetWithoutHeaders() throws Exception { OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http://somedomain/foo", /* requestId */ 0, /* headers */ JavaOnlyArray.of(), /* body */ null, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); assertThat(argumentCaptor.getValue().url().toString()).isEqualTo("http://somedomain/foo"); // We set the User-Agent header by default assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(1); assertThat(argumentCaptor.getValue().method()).isEqualTo("GET"); }
@Test public void testFailGetWithInvalidHeadersStruct() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); List<JavaOnlyArray> invalidHeaders = Arrays.asList(JavaOnlyArray.of("foo")); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http://somedoman/foo", /* requestId */ 0, /* headers */ JavaOnlyArray.from(invalidHeaders), /* body */ null, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0); verifyErrorEmit(emitter, 0); }
@Test public void testFailPostWithoutContentType() throws Exception { RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); ReactApplicationContext context = mock(ReactApplicationContext.class); when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter); OkHttpClient httpClient = mock(OkHttpClient.class); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); JavaOnlyMap body = new JavaOnlyMap(); body.putString("string", "This is request body"); mockEvents(); networkingModule.sendRequest( mock(ExecutorToken.class), "POST", "http://somedomain/bar", 0, JavaOnlyArray.of(), body, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0); verifyErrorEmit(emitter, 0); }
@Test public void testHeaders() throws Exception { OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Call callMock = mock(Call.class); return callMock; } }); OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); NetworkingModule networkingModule = new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient); List<JavaOnlyArray> headers = Arrays.asList( JavaOnlyArray.of("Accept", "text/plain"), JavaOnlyArray.of("User-Agent", "React test agent/1.0")); networkingModule.sendRequest( mock(ExecutorToken.class), "GET", "http://someurl/baz", 0, JavaOnlyArray.from(headers), null, /* responseType */ "text", /* useIncrementalUpdates*/ true, /* timeout */ 0); ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class); verify(httpClient).newCall(argumentCaptor.capture()); Headers requestHeaders = argumentCaptor.getValue().headers(); assertThat(requestHeaders.size()).isEqualTo(2); assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain"); assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0"); }
private void readWithProgress( ExecutorToken executorToken, int requestId, ResponseBody responseBody) throws IOException { Reader reader = responseBody.charStream(); try { StringBuilder sb = new StringBuilder(getBufferSize(responseBody)); char[] buffer = new char[MIN_BUFFER_SIZE]; int read; long last = System.nanoTime(); while ((read = reader.read(buffer)) != -1) { sb.append(buffer, 0, read); long now = System.nanoTime(); if (shouldDispatch(now, last)) { onDataReceived(executorToken, requestId, sb.toString()); sb.setLength(0); last = now; } } if (sb.length() > 0) { onDataReceived(executorToken, requestId, sb.toString()); } } finally { reader.close(); } }
private void onDataReceived(ExecutorToken ExecutorToken, int requestId, String data) { WritableArray args = Arguments.createArray(); args.pushInt(requestId); args.pushString(data); getEventEmitter(ExecutorToken).emit("didReceiveNetworkData", args); }
private void onRequestError(ExecutorToken ExecutorToken, int requestId, String error) { WritableArray args = Arguments.createArray(); args.pushInt(requestId); args.pushString(error); getEventEmitter(ExecutorToken).emit("didCompleteNetworkResponse", args); }