diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 2bd3dce70efa..18de3c4152ea 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -159,26 +159,24 @@ let Image = (props: ImagePropsType, forwardedRef) => { source = null; } - let style; - let sources; - if (source?.uri != null) { - const {width, height} = source; - style = flattenStyle([{width, height}, styles.base, props.style]); - sources = [{uri: source.uri}]; - } else { - style = flattenStyle([styles.base, props.style]); - sources = source; - } + const sourceIsSingleImage = !Array.isArray(source) && source != null; + const style = flattenStyle([ + sourceIsSingleImage && { + width: source.width, + height: source.height, + }, + styles.base, + props.style, + ]); const {onLoadStart, onLoad, onLoadEnd, onError} = props; const nativeProps = { ...props, style, shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd || onError), - src: sources, + src: sourceIsSingleImage ? [source] : source, /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - headers: source?.headers, defaultSrc: defaultSource ? defaultSource.uri : null, loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/image/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/image/BUCK index 7ebd194664fa..0bc96be168ba 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/image/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/image/BUCK @@ -21,7 +21,7 @@ rn_android_library( react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/modules/fresco:fresco"), react_native_target("java/com/facebook/react/module/annotations:annotations"), - react_native_target("java/com/facebook/react/views/imagehelper:imagehelper"), + react_native_target("java/com/facebook/react/views/imagehelper:imagesource"), react_native_target("java/com/facebook/react/views/image:image"), ], exported_deps = [ diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.java index c2fb799d34e7..9537e8108ae8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.java @@ -96,51 +96,7 @@ private ImagePipeline getImagePipeline() { */ @ReactMethod public void getSize(final String uriString, final Promise promise) { - if (uriString == null || uriString.isEmpty()) { - promise.reject(ERROR_INVALID_URI, "Cannot get the size of an image for an empty URI"); - return; - } - - ImageSource source = new ImageSource(getReactApplicationContext(), uriString); - ImageRequest request = ImageRequestBuilder.newBuilderWithSource(source.getUri()).build(); - - DataSource> dataSource = - getImagePipeline().fetchDecodedImage(request, getCallerContext()); - - DataSubscriber> dataSubscriber = - new BaseDataSubscriber>() { - @Override - protected void onNewResultImpl( - DataSource> dataSource) { - if (!dataSource.isFinished()) { - return; - } - CloseableReference ref = dataSource.getResult(); - if (ref != null) { - try { - CloseableImage image = ref.get(); - - WritableMap sizes = Arguments.createMap(); - sizes.putInt("width", image.getWidth()); - sizes.putInt("height", image.getHeight()); - - promise.resolve(sizes); - } catch (Exception e) { - promise.reject(ERROR_GET_SIZE_FAILURE, e); - } finally { - CloseableReference.closeSafely(ref); - } - } else { - promise.reject(ERROR_GET_SIZE_FAILURE); - } - } - - @Override - protected void onFailureImpl(DataSource> dataSource) { - promise.reject(ERROR_GET_SIZE_FAILURE, dataSource.getFailureCause()); - } - }; - dataSource.subscribe(dataSubscriber, CallerThreadExecutor.getInstance()); + getSizeWithHeaders(uriString, null, promise); } /** @@ -159,11 +115,8 @@ public void getSizeWithHeaders( return; } - ImageSource source = new ImageSource(getReactApplicationContext(), uriString); - ImageRequestBuilder imageRequestBuilder = - ImageRequestBuilder.newBuilderWithSource(source.getUri()); - ImageRequest request = - ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, headers); + ImageSource source = new ImageSource(getReactApplicationContext(), uriString, headers); + ImageRequest request = source.createImageRequest(); DataSource> dataSource = getImagePipeline().fetchDecodedImage(request, getCallerContext()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK index a13531e19271..4b0cfcef618a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK @@ -61,6 +61,7 @@ rn_android_library( react_native_target("java/com/facebook/react/modules/fresco:fresco"), react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), react_native_target("java/com/facebook/react/views/imagehelper:withmultisource"), + react_native_target("java/com/facebook/react/views/imagehelper:imagesource"), ], exported_deps = [ ":imageevents", diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java index 187958c6ee4d..619bbc301d55 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java @@ -239,11 +239,6 @@ public void setLoadHandlersRegistered(ReactImageView view, boolean shouldNotifyL view.setShouldNotifyLoadEvents(shouldNotifyLoadEvents); } - @ReactProp(name = "headers") - public void setHeaders(ReactImageView view, ReadableMap headers) { - view.setHeaders(headers); - } - @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { @Nullable diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java index b841ddbec1b5..27f821153dd4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java @@ -207,7 +207,6 @@ public CloseableReference process(Bitmap source, PlatformBitmapFactory b private @Nullable Object mCallerContext; private int mFadeDurationMs = -1; private boolean mProgressiveRenderingEnabled; - private ReadableMap mHeaders; // We can't specify rounding in XML, so have to do so here private static GenericDraweeHierarchy buildHierarchy(Context context) { @@ -385,14 +384,15 @@ public void setSource(@Nullable ReadableArray sources) { List tmpSources = new LinkedList<>(); if (sources == null || sources.size() == 0) { - ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI); + ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI, null); tmpSources.add(imageSource); } else { // Optimize for the case where we have just one uri, case in which we don't need the sizes if (sources.size() == 1) { ReadableMap source = sources.getMap(0); String uri = source.getString("uri"); - ImageSource imageSource = new ImageSource(getContext(), uri); + ReadableMap headers = source.getMap("headers"); + ImageSource imageSource = new ImageSource(getContext(), uri, headers); tmpSources.add(imageSource); if (Uri.EMPTY.equals(imageSource.getUri())) { warnImageSource(uri); @@ -401,9 +401,10 @@ public void setSource(@Nullable ReadableArray sources) { for (int idx = 0; idx < sources.size(); idx++) { ReadableMap source = sources.getMap(idx); String uri = source.getString("uri"); + ReadableMap headers = source.getMap("headers"); ImageSource imageSource = new ImageSource( - getContext(), uri, source.getDouble("width"), source.getDouble("height")); + getContext(), uri, headers, source.getDouble("width"), source.getDouble("height")); tmpSources.add(imageSource); if (Uri.EMPTY.equals(imageSource.getUri())) { warnImageSource(uri); @@ -475,10 +476,6 @@ private void getCornerRadii(float[] computedCorners) { : defaultBorderRadius; } - public void setHeaders(ReadableMap headers) { - mHeaders = headers; - } - public void maybeUpdateView() { if (!mIsDirty) { return; @@ -561,14 +558,14 @@ public void maybeUpdateView() { ResizeOptions resizeOptions = doResize ? new ResizeOptions(getWidth(), getHeight()) : null; ImageRequestBuilder imageRequestBuilder = - ImageRequestBuilder.newBuilderWithSource(mImageSource.getUri()) + mImageSource.createImageRequestBuilder() .setPostprocessor(postprocessor) .setResizeOptions(resizeOptions) .setAutoRotateEnabled(true) .setProgressiveRenderingEnabled(mProgressiveRenderingEnabled); ImageRequest imageRequest = - ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders); + mImageSource.createImageRequestFromBuilder(imageRequestBuilder); if (mGlobalImageLoadListener != null) { mGlobalImageLoadListener.onLoadAttempt(mImageSource.getUri()); @@ -585,7 +582,7 @@ public void maybeUpdateView() { if (mCachedImageSource != null) { ImageRequest cachedImageRequest = - ImageRequestBuilder.newBuilderWithSource(mCachedImageSource.getUri()) + mCachedImageSource.createImageRequestBuilder() .setPostprocessor(postprocessor) .setResizeOptions(resizeOptions) .setAutoRotateEnabled(true) @@ -656,7 +653,7 @@ private boolean shouldUseRoundedCornerPostprocessing() { private void setSourceImage() { mImageSource = null; if (mSources.isEmpty()) { - ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI); + ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI, null); mSources.add(imageSource); } else if (hasMultipleSources()) { MultiSourceResult multiSource = diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/BUCK index 3776c3389f84..cb5d50c8e9c1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/BUCK @@ -4,7 +4,7 @@ rn_android_library( name = "imagehelper", srcs = glob( ["*.java"], - exclude = ["MultiSourceHelper.java"], + exclude = ["MultiSourceHelper.java","ImageSource.java"], ), autoglob = False, is_androidx = True, @@ -38,3 +38,22 @@ rn_android_library( ":imagehelper", ], ) + +rn_android_library( + name = "imagesource", + srcs = ["ImageSource.java"], + autoglob = False, + is_androidx = True, + labels = ["supermodule:xplat/default/public.react_native.infra"], + visibility = [ + "PUBLIC", + ], + deps = [ + react_native_dep("third-party/android/androidx:annotation"), + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/modules/fresco:fresco"), + ] +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ImageSource.java b/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ImageSource.java index 94a3e1c8ace9..d7fa4665b7e7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ImageSource.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ImageSource.java @@ -10,19 +10,27 @@ import android.content.Context; import android.net.Uri; import androidx.annotation.Nullable; + +import com.facebook.imagepipeline.request.ImageRequest; +import com.facebook.imagepipeline.request.ImageRequestBuilder; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.modules.fresco.ReactNetworkImageRequest; + import java.util.Objects; /** Class describing an image source (network URI or resource) and size. */ public class ImageSource { - private @Nullable Uri mUri; - private String mSource; - private double mSize; + private final @Nullable Uri mUri; + private final ReadableMap mHeaders; + private final String mSource; + private final double mSize; private boolean isResource; - public ImageSource(Context context, String source, double width, double height) { + public ImageSource(Context context, String source, ReadableMap headers, double width, double height) { mSource = source; + mHeaders = headers; mSize = width * height; // Important: we compute the URI here so that we don't need to hold a reference to the context, @@ -46,8 +54,27 @@ public int hashCode() { return Objects.hash(mUri, mSource, mSize, isResource); } + public ImageSource(Context context, String source, ReadableMap headers) { + this(context, source, headers, 0.0d, 0.0d); + } + + /** @deprecated for library backwards compatibility only */ public ImageSource(Context context, String source) { - this(context, source, 0.0d, 0.0d); + this(context, source, null); + } + + public ImageRequestBuilder createImageRequestBuilder() { + return ImageRequestBuilder.newBuilderWithSource(getUri()); + } + + public ImageRequest createImageRequestFromBuilder(final ImageRequestBuilder imageRequestBuilder) { + return ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders); + } + + public ImageRequest createImageRequest() { + return createImageRequestFromBuilder( + createImageRequestBuilder() + ); } /** Get the source of this image, as it was passed to the constructor. */