diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/bridge/ArgumentsTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/bridge/ArgumentsTest.java new file mode 100644 index 00000000000000..bd0932b6304a9f --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/bridge/ArgumentsTest.java @@ -0,0 +1,89 @@ +package com.facebook.react.bridge; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.facebook.soloader.SoLoader; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.facebook.react.bridge.Arguments.fromBundle; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(AndroidJUnit4.class) +public class ArgumentsTest { + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + SoLoader.init(context, false); + } + + @Test + public void testFromBundle() { + verifyBundle(createBundle()); + } + + /** + * When passing a bundle via {@link Intent} extras, it gets parceled and unparceled. + * Any array of bundles will return as an array of {@link Parcelable} instead. This test + * verifies that {@link Arguments#fromArray} handles this situation correctly. + */ + @Test + public void testFromMarshaledBundle() { + verifyBundle(marshalAndUnmarshalBundle(createBundle())); + } + + private void verifyBundle(@NonNull Bundle bundle) { + WritableMap map = fromBundle(bundle); + assertNotNull(map); + + assertEquals(ReadableType.Array, map.getType("children")); + ReadableArray children = map.getArray("children"); + assertNotNull(children); + assertEquals(1, children.size()); + + assertEquals(ReadableType.Map, children.getType(0)); + ReadableMap child = children.getMap(0); + assertNotNull(child); + assertEquals("exampleChild", child.getString("exampleChildKey")); + } + + @NonNull + private Bundle marshalAndUnmarshalBundle(@NonNull Bundle bundle) { + Parcel parcel = null; + try { + parcel = Parcel.obtain(); + bundle.writeToParcel(parcel, 0); + + byte[] bytes = parcel.marshall(); + parcel.unmarshall(bytes, 0, bytes.length); + parcel.setDataPosition(0); + return Bundle.CREATOR.createFromParcel(parcel); + } finally { + if (parcel != null) { + parcel.recycle(); + } + } + } + + @NonNull + private Bundle createBundle() { + Bundle bundle = new Bundle(); + Bundle[] children = new Bundle[1]; + children[0] = new Bundle(); + children[0].putString("exampleChildKey", "exampleChild"); + bundle.putSerializable("children", children); + return bundle; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/Arguments.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/Arguments.java index e17e3c1aca1166..9d4dc86014a88b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/Arguments.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/Arguments.java @@ -7,6 +7,8 @@ package com.facebook.react.bridge; import android.os.Bundle; +import android.os.Parcelable; + import androidx.annotation.Nullable; import java.lang.reflect.Array; import java.util.AbstractList; @@ -218,6 +220,14 @@ public static WritableArray fromArray(Object array) { for (boolean v : (boolean[]) array) { catalystArray.pushBoolean(v); } + } else if (array instanceof Parcelable[]) { + for (Parcelable v : (Parcelable[]) array) { + if (v instanceof Bundle) { + catalystArray.pushMap(fromBundle((Bundle) v)); + } else { + throw new IllegalArgumentException("Unexpected array member type " + v.getClass()); + } + } } else { throw new IllegalArgumentException("Unknown array type " + array.getClass()); }