Show bundle loading progress on Android

Summary:
This implements a loading banner like on iOS that shows the progress of the packager.

![](https://media.giphy.com/media/l4FGoepExkpOeXtTO/giphy.gif)

**Test plan**
- Tested that it displays similar messages as it does on iOS and also that is show the right message when waiting for the remote debugger.
- Tested that errors are still shown properly.
- Tested that it works with packagers that don't support multipart response (add && false in https://github.com/facebook/react-native/blob/master/packager/src/Server/MultipartResponse.js#L81).
- Run new unit tests.
- Tested that backgrounding / foregrounding the app hides / show the banner properly.
Closes https://github.com/facebook/react-native/pull/12674

Differential Revision: D4673638

Pulled By: mkonicek

fbshipit-source-id: b2a1163de3d0792cf481d7111231a065f80a9594
This commit is contained in:
Janic Duplessis
2017-03-09 10:30:51 -08:00
committed by Facebook Github Bot
parent e5ebdd8458
commit 231bf7c68b
8 changed files with 580 additions and 69 deletions

View File

@@ -16,6 +16,7 @@ rn_robolectric_test(
react_native_dep("third-party/java/mockito:mockito"),
react_native_dep("third-party/java/okhttp:okhttp3"),
react_native_dep("third-party/java/okhttp:okhttp3-ws"),
react_native_dep("third-party/java/okio:okio"),
react_native_dep("third-party/java/robolectric3/robolectric:robolectric"),
react_native_target("java/com/facebook/react:react"),
react_native_target("java/com/facebook/react/bridge:bridge"),

View File

@@ -0,0 +1,143 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.devsupport;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.io.IOException;
import java.util.Map;
import okio.Buffer;
import okio.ByteString;
import static org.fest.assertions.api.Assertions.assertThat;
@RunWith(RobolectricTestRunner.class)
public class MultipartStreamReaderTest {
class CallCountTrackingChunkCallback implements MultipartStreamReader.ChunkCallback {
private int mCount = 0;
@Override
public void execute(Map<String, String> headers, Buffer body, boolean done) throws IOException {
mCount++;
}
public int getCallCount() {
return mCount;
}
}
@Test
public void testSimpleCase() throws IOException {
ByteString response = ByteString.encodeUtf8(
"preable, should be ignored\r\n" +
"--sample_boundary\r\n" +
"Content-Type: application/json; charset=utf-8\r\n" +
"Content-Length: 2\r\n\r\n" +
"{}\r\n" +
"--sample_boundary--\r\n" +
"epilogue, should be ignored");
Buffer source = new Buffer();
source.write(response);
MultipartStreamReader reader = new MultipartStreamReader(source, "sample_boundary");
CallCountTrackingChunkCallback callback = new CallCountTrackingChunkCallback() {
@Override
public void execute(Map<String, String> headers, Buffer body, boolean done) throws IOException {
super.execute(headers, body, done);
assertThat(done).isTrue();
assertThat(headers.get("Content-Type")).isEqualTo("application/json; charset=utf-8");
assertThat(body.readUtf8()).isEqualTo("{}");
}
};
boolean success = reader.readAllParts(callback);
assertThat(callback.getCallCount()).isEqualTo(1);
assertThat(success).isTrue();
}
@Test
public void testMultipleParts() throws IOException {
ByteString response = ByteString.encodeUtf8(
"preable, should be ignored\r\n" +
"--sample_boundary\r\n" +
"1\r\n" +
"--sample_boundary\r\n" +
"2\r\n" +
"--sample_boundary\r\n" +
"3\r\n" +
"--sample_boundary--\r\n" +
"epilogue, should be ignored");
Buffer source = new Buffer();
source.write(response);
MultipartStreamReader reader = new MultipartStreamReader(source, "sample_boundary");
CallCountTrackingChunkCallback callback = new CallCountTrackingChunkCallback() {
@Override
public void execute(Map<String, String> headers, Buffer body, boolean done) throws IOException {
super.execute(headers, body, done);
assertThat(done).isEqualTo(getCallCount() == 3);
assertThat(body.readUtf8()).isEqualTo(String.valueOf(getCallCount()));
}
};
boolean success = reader.readAllParts(callback);
assertThat(callback.getCallCount()).isEqualTo(3);
assertThat(success).isTrue();
}
@Test
public void testNoDelimiter() throws IOException {
ByteString response = ByteString.encodeUtf8("Yolo");
Buffer source = new Buffer();
source.write(response);
MultipartStreamReader reader = new MultipartStreamReader(source, "sample_boundary");
CallCountTrackingChunkCallback callback = new CallCountTrackingChunkCallback();
boolean success = reader.readAllParts(callback);
assertThat(callback.getCallCount()).isEqualTo(0);
assertThat(success).isFalse();
}
@Test
public void testNoCloseDelimiter() throws IOException {
ByteString response = ByteString.encodeUtf8(
"preable, should be ignored\r\n" +
"--sample_boundary\r\n" +
"Content-Type: application/json; charset=utf-8\r\n" +
"Content-Length: 2\r\n\r\n" +
"{}\r\n" +
"--sample_boundary\r\n" +
"incomplete message...");
Buffer source = new Buffer();
source.write(response);
MultipartStreamReader reader = new MultipartStreamReader(source, "sample_boundary");
CallCountTrackingChunkCallback callback = new CallCountTrackingChunkCallback();
boolean success = reader.readAllParts(callback);
assertThat(callback.getCallCount()).isEqualTo(1);
assertThat(success).isFalse();
}
}