Skip to content

Commit 7795a67

Browse files
Jyrno42facebook-github-bot
authored andcommitted
Android: Add error description to Image onError callback (#22737)
Summary: fixes #19073 Changelog: ---------- [Android] [Fixed] - Add error description to Image onError callback Pull Request resolved: #22737 Differential Revision: D13676224 Pulled By: hramos fbshipit-source-id: 0dea7e97ae6517b8980ad02827f19d22cd3ef933
1 parent 527fc9d commit 7795a67

File tree

7 files changed

+134
-5
lines changed

7 files changed

+134
-5
lines changed

ReactAndroid/src/androidTest/AndroidManifest.xml

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
77
<!-- needed for screenshot tests -->
88
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
9+
<!-- needed for image onError tests -->
10+
<uses-permission android:name="android.permission.INTERNET" />
911

1012
<application
1113
android:hardwareAccelerated="false">

ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
88
<!-- needed for screenshot tests -->
99
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
10+
<!-- needed for image onError tests -->
11+
<uses-permission android:name="android.permission.INTERNET" />
1012

1113
<application
1214
android:hardwareAccelerated="false">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.tests;
9+
10+
import android.view.View;
11+
import com.facebook.react.testing.ReactAppInstrumentationTestCase;
12+
import com.facebook.react.testing.ReactInstanceSpecForTest;
13+
import com.facebook.react.testing.StringRecordingModule;
14+
15+
/**
16+
* Simple test case to check that onError does not get called with undefined
17+
*/
18+
public class ImageErrorTestCase extends ReactAppInstrumentationTestCase {
19+
20+
private StringRecordingModule mStringRecordingModule;
21+
22+
@Override
23+
protected String getReactApplicationKeyUnderTest() {
24+
return "ImageErrorTestApp";
25+
}
26+
27+
public void testErrorHasCause() throws Exception {
28+
assertNotNull(getViewByTestId("image-1"));
29+
assertNotNull(getViewByTestId("image-2"));
30+
assertNotNull(getViewByTestId("image-3"));
31+
32+
Thread.sleep(3000);
33+
34+
assertEquals(3, mStringRecordingModule.getCalls().size());
35+
assertEquals("Got error: Unsupported uri scheme! Uri is: ", mStringRecordingModule.getCalls().get(0));
36+
assertEquals("Got error: /does/not/exist: open failed: ENOENT (No such file or directory)", mStringRecordingModule.getCalls().get(1));
37+
assertEquals("Got error: Unexpected HTTP code Response{protocol=http/1.1, code=404, message=Not Found, url=https://typo_error_facebook.github.io/react/logo-og.png}", mStringRecordingModule.getCalls().get(2));
38+
}
39+
40+
@Override
41+
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
42+
mStringRecordingModule = new StringRecordingModule();
43+
return super.createReactInstanceSpecForTest()
44+
.addNativeModule(mStringRecordingModule);
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
*/
9+
10+
'use strict';
11+
12+
const React = require('React');
13+
const Image = require('Image');
14+
const StyleSheet = require('StyleSheet');
15+
const View = require('View');
16+
17+
const RecordingModule = require('NativeModules').Recording;
18+
19+
class ImageErrorTestApp extends React.Component {
20+
onError = e => {
21+
RecordingModule.record('Got error: ' + e.nativeEvent.error);
22+
};
23+
24+
render() {
25+
// For some reason image-2 needs explicit height. Without it onError is not triggered.
26+
return (
27+
<View>
28+
<Image
29+
testID="image-1"
30+
source={{uri: '/does/not/exist'}}
31+
onError={this.onError}
32+
/>
33+
<Image
34+
testID="image-2"
35+
source={{uri: 'file:///does/not/exist'}}
36+
style={styles.image}
37+
onError={this.onError}
38+
/>
39+
<Image
40+
testID="image-3"
41+
source={{
42+
uri: 'https://TYPO_ERROR_facebook.github.io/react/logo-og.png',
43+
}}
44+
onError={this.onError}
45+
/>
46+
</View>
47+
);
48+
}
49+
}
50+
51+
const styles = StyleSheet.create({
52+
image: {
53+
height: 50,
54+
width: 50,
55+
},
56+
});
57+
58+
module.exports = ImageErrorTestApp;

ReactAndroid/src/androidTest/js/TestBundle.js

+4
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ const apps = [
5858
appKey: 'ImageOverlayColorTestApp',
5959
component: () => require('ImageOverlayColorTestApp'),
6060
},
61+
{
62+
appKey: 'ImageErrorTestApp',
63+
component: () => require('ImageErrorTestApp'),
64+
},
6165
{
6266
appKey: 'InitialPropsTestApp',
6367
component: () => require('InitialPropsTestApp'),

ReactAndroid/src/main/java/com/facebook/react/views/image/ImageLoadEvent.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,18 @@ public class ImageLoadEvent extends Event<ImageLoadEvent> {
3333
private final @Nullable String mImageUri;
3434
private final int mWidth;
3535
private final int mHeight;
36+
private final @Nullable String mImageError;
3637

3738
public ImageLoadEvent(int viewId, @ImageEventType int eventType) {
3839
this(viewId, eventType, null);
3940
}
4041

42+
public ImageLoadEvent(int viewId, @ImageEventType int eventType, boolean error, String message) {
43+
this(viewId, eventType, null, 0, 0, message);
44+
}
45+
4146
public ImageLoadEvent(int viewId, @ImageEventType int eventType, String imageUri) {
42-
this(viewId, eventType, imageUri, 0, 0);
47+
this(viewId, eventType, imageUri, 0, 0, null);
4348
}
4449

4550
public ImageLoadEvent(
@@ -48,11 +53,22 @@ public ImageLoadEvent(
4853
@Nullable String imageUri,
4954
int width,
5055
int height) {
56+
this(viewId, eventType, imageUri, width, height, null);
57+
}
58+
59+
public ImageLoadEvent(
60+
int viewId,
61+
@ImageEventType int eventType,
62+
@Nullable String imageUri,
63+
int width,
64+
int height,
65+
@Nullable String message) {
5166
super(viewId);
5267
mEventType = eventType;
5368
mImageUri = imageUri;
5469
mWidth = width;
5570
mHeight = height;
71+
mImageError = message;
5672
}
5773

5874
public static String eventNameForType(@ImageEventType int eventType) {
@@ -88,7 +104,7 @@ public short getCoalescingKey() {
88104
public void dispatch(RCTEventEmitter rctEventEmitter) {
89105
WritableMap eventData = null;
90106

91-
if (mImageUri != null || mEventType == ON_LOAD) {
107+
if (mImageUri != null || (mEventType == ON_LOAD || mEventType == ON_ERROR)) {
92108
eventData = Arguments.createMap();
93109

94110
if (mImageUri != null) {
@@ -103,6 +119,8 @@ public void dispatch(RCTEventEmitter rctEventEmitter) {
103119
source.putString("url", mImageUri);
104120
}
105121
eventData.putMap("source", source);
122+
} else if (mEventType == ON_ERROR) {
123+
eventData.putString("error", mImageError);
106124
}
107125
}
108126

ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,8 @@ public void onFinalImageSet(
262262
@Override
263263
public void onFailure(String id, Throwable throwable) {
264264
mEventDispatcher.dispatchEvent(
265-
new ImageLoadEvent(getId(), ImageLoadEvent.ON_ERROR));
266-
mEventDispatcher.dispatchEvent(
267-
new ImageLoadEvent(getId(), ImageLoadEvent.ON_LOAD_END));
265+
new ImageLoadEvent(getId(), ImageLoadEvent.ON_ERROR,
266+
true, throwable.getMessage()));
268267
}
269268
};
270269
}

0 commit comments

Comments
 (0)