Camera crashes on simulator and android device
See original GitHub issue🐛 Bug Report
Summary of Issue
Camera crashes when running caemra.takePictureAsync with my code and also sample code on Camera documentation.
Environment - output of expo diagnostics
& the platform(s) you’re targeting
Expo CLI 3.27.14 environment info: System: OS: macOS Mojave 10.14.4 Shell: 3.2.57 - /bin/bash Binaries: Node: 10.16.3 - ~/.nvm/versions/node/v10.16.3/bin/node Yarn: 1.15.2 - /usr/local/bin/yarn npm: 6.9.0 - ~/.nvm/versions/node/v10.16.3/bin/npm SDKs: iOS SDK: Platforms: iOS 12.4, macOS 10.14, tvOS 12.4, watchOS 5.3 IDEs: Xcode: 10.3/10G8 - /usr/bin/xcodebuild npmPackages: expo: ^39.0.0 => 39.0.3 react: 16.13.1 => 16.13.1 react-native: https://github.com/expo/react-native/archive/sdk-39.0.3.tar.gz => 0.63.2 react-navigation: ^4.3.9 => 4.4.2 npmGlobalPackages: expo-cli: 3.27.14 Expo Workflow: managed Targetting Android.
Reproducible Demo
`import React from ‘react’; import { View, Text } from ‘react-native’; import { Camera } from ‘expo-camera’; import * as Permissions from ‘expo-permissions’; import Toolbar from ‘…/components/toolbar’; import Gallery from ‘…/components/gallery’; import db from ‘…/sqlite’; import * as MediaLibrary from ‘expo-media-library’; import * as ImageManipulator from ‘expo-image-manipulator’; import { PinchGestureHandler } from ‘react-native-gesture-handler’; import { Asset } from ‘expo-asset’; import * as Device from ‘expo-device’; import { DeviceMotion } from ‘expo-sensors’;
import styles from ‘…/styles/index.js’;
export default class CameraPage extends React.Component { camera = null;
state = {
captures: [],
// trun off flash by default
capturing: null,
// start the back camera by default
cameraType: Camera.Constants.Type.back,
hasCameraPermission: null,
hasCameraRollPermission: null,
currentOrderId: this.props.navigation.state.params.id,
currentNarrativeId: this.props.navigation.state.params.narrativeId,
catId: this.props.navigation.state.params.catId,
catIndex: this.props.navigation.state.params.catIndex,
subCatId: this.props.navigation.state.params.subCatId,
coverPhoto: this.props.navigation.state.params.coverPhoto,
concernId: this.props.navigation.state.params.concernId,
gestureState: false,
cameraZoom: 'in',
initialPinchScale: null,
zoom: 0,
imgPortrait: true,
deviceIs: '',
rotate: 0,
};
setFlashMode = (flashMode) => this.setState({ flashMode });
setCameraType = (cameraType) => this.setState({ cameraType });
async askCameraRollPermissions() {
const cameraRoll = await Permissions.askAsync(Permissions.CAMERA_ROLL);
const hasCameraRollPermission = (cameraRoll.status === 'granted');
this.setState({ hasCameraRollPermission });
}
async orderPhotoAlbum() {
const albumResult = await MediaLibrary.getAlbumAsync(this.state.currentOrderId);
console.log('this is albumresult');
console.log(albumResult);
if(!albumResult || albumResult == null) {
console.log('albumResult')
this.loadAssetLocal();
} else {
console.log('else albumResult')
this.setState({ albumId: albumResult.id })
}
}
async loadAssetLocal() {
let loadedImage = await Asset.fromModule(require('../../assets/splash.jpeg'));
if (!loadedImage.localUri) {
return Asset.loadAsync(require('../../assets/splash.jpeg')).then(async () => {
loadedImage = await Asset.fromModule(require('../../assets/splash.jpeg'));
const testLoad = await MediaLibrary.createAssetAsync(loadedImage.localUri).then(async asset => {
console.log('running testLoad');
const albumCreated = await MediaLibrary.createAlbumAsync(this.state.currentOrderId, asset, false);
this.setState({ albumId: albumCreated.id })
})
})
}
}
changeZoom = () => {
const { zoom } = this.state;
let zoomLevel = zoom;
if( zoom <= 1) {
zoomLevel = zoomLevel + .2;
this.setState({ zoom: zoomLevel });
}
}
changeImgDirection = direction => {
const { imgPortrait } = this.state;
this.setState({ imgPortrait: !imgPortrait });
}
calculateRotation = ({rotation: {beta, gamma}}) => {
let absGamma = Math.abs(gamma)
let absBeta = Math.abs(beta)
let rotate = 0
if (absGamma <= 0.04 && absBeta <= 0.24) {
// Portrait mode, on a flat surface.
rotate = 0
} else if ((absGamma <= 1.0 || absGamma >= 2.3) && absBeta >= 0.5) {
// General Portrait mode, accounting for forward and back tilt on the top of the phone.
rotate = 0
} else {
if (gamma < 0) {
// Landscape mode with the top of the phone to the left.
rotate = -90
} else {
// Landscape mode with the top of the phone to the right.
rotate = 90
}
}
if(rotate != this.state.rotate) {
this.setState({rotate})
}
}
onPinchGestureEvent = event => {
const { gestureState, cameraZoom, initialPinchScale } = this.state;
let zoom = this.state.zoom;
if (gestureState == true) {
if (initialPinchScale > event.nativeEvent.scale) {
if ( zoom <= 1 ) {
zoom = zoom + .002;
if(zoom <= 1) {
this.setState({ zoom: zoom });
}
}
}
if (initialPinchScale < event.nativeEvent.scale) {
if ( zoom >= 0 ) {
zoom = zoom - .002;
if(zoom >= 0) {
this.setState({ zoom: zoom });
}
}
}
// if (cameraZoom == 'in')
// if (event.nativeEvent.scale > initialPinchScale) {
// return 'nothing to scale';
// } else {
// if ( zoom <= 1 ) {
// zoom = zoom + .002;
// this.setState({ zoom: zoom });
// }
// }
} else {
this.setState({ gestureState: true, initialPinchScale: event.nativeEvent.scale })
}
}
savePictures = () => {
const { hasCameraRollPermission } = this.state;
if (hasCameraRollPermission === null) {
this.askCameraRollPermissions();
} else if (hasCameraRollPermission === false) {
this.askCameraRollPermissions();
}
const { currentNarrativeId, currentOrderId, catId, catIndex, subCatId, concernId } = this.state;
this.state.captures.map(x => {
db.transaction(tx => {
if( this.state.coverPhoto == true ) {
tx.executeSql(
'INSERT into dr_report_narrative_images (narrative_id, uri, order_id, catId ) values (?, ?, ?, ?)',
[ currentNarrativeId, x.uri, currentOrderId, 'cover' ],
(trans, result) => {
});
} else {
tx.executeSql(
'INSERT into dr_report_narrative_images (concern_id, narrative_id, uri, order_id, catId, subCatId, catIndex ) values (?, ?, ?, ?, ?, ?, ?)',
[concernId, currentNarrativeId, x.uri, currentOrderId, catId, subCatId, catIndex ],
(trans, result) => {
});
}
},
(err) => console.error(err),
() => {
this.state.captures.forEach(async (el) => {
const savedAsset = await MediaLibrary.createAssetAsync(el.uri);
await MediaLibrary.addAssetsToAlbumAsync([savedAsset], this.state.albumId, false);
})
this.props.navigation.goBack();
}
);
});
}
activateDeviceMotion = async () => {
if(DeviceMotion.isAvailableAsync()) {
DeviceMotion.setUpdateInterval(1000)
const devListener = await DeviceMotion.addListener(this.calculateRotation);
}
}
handleShortCapture = async () => {
const takePicOptions = {
skipProcessing: false,
exif: true,
}
const photoData = await this.camera.takePictureAsync(takePicOptions).then(
async (data) => {
// console.log(data);
// let rotation = 0;
// if(!this.state.imgPortrait) {
// rotation = -90
// }
// const saveOptions = {
// compress: 1, base64: true
// }
// await ImageManipulator.manipulateAsync(
// data.uri,
// [ { rotate: this.state.rotate },
// { resize: { width: 900 } }], saveOptions
// ). then(img => {
// this.setState({ capturing: false, captures: [img, ...this.state.captures] })
// })
}
)
}
async componentDidMount() {
console.log('in did mount')
this.activateDeviceMotion();
const deviceIs = Device.osName;
const camera = await Permissions.askAsync(Permissions.CAMERA);
const hasCameraPermission = (camera.status === 'granted');
this.setState({ hasCameraPermission, deviceIs });
const askCameraRoll = await this.askCameraRollPermissions();
this.orderPhotoAlbum();
};
componentWillUnmount() {
DeviceMotion.removeAllListeners()
}
render() {
const { hasCameraPermission, flashMode, cameraType, capturing,
captures, zoom, imgPortrait, deviceIs } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>Access to camera has been denied.</Text>;
}
return (
<React.Fragment>
<PinchGestureHandler
onGestureEvent={this.onPinchGestureEvent}
>
<View>
<Camera
type={cameraType}
flashMode={flashMode}
zoom={zoom}
style={styles.preview}
ref={camera => this.camera = camera}
/>
</View>
</PinchGestureHandler>
{captures.length > 0 && <Gallery captures={captures}/>}
<Toolbar
capturing={capturing}
flashMode={flashMode}
cameraType={cameraType}
setFlashMode={this.setFlashMode}
setCameraType={this.setCameraType}
savePictures={this.savePictures}
onShortCapture={this.handleShortCapture}
changeZoom={this.changeZoom}
changeImgDirection={this.changeImgDirection}
imgPortrait={imgPortrait}
deviceIs={deviceIs}
/>
</React.Fragment>
);
};
}; `
Steps to Reproduce
Run on android simulator from mac os. When clicking and activating handleShortCapture I get the following error:
2020-10-09 16:10:17.502 11055-11364/? E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #7 Process: host.exp.exponent, PID: 11055 java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$4.done(AsyncTask.java:399) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383) at java.util.concurrent.FutureTask.setException(FutureTask.java:252) at java.util.concurrent.FutureTask.run(FutureTask.java:271) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:919) Caused by: java.lang.NullPointerException: Attempt to get length of null array at java.io.ByteArrayInputStream.<init>(ByteArrayInputStream.java:106) at abi39_0_0.expo.modules.camera.tasks.ResolveTakenPictureAsyncTask.doInBackground(ResolveTakenPictureAsyncTask.java:7) at abi39_0_0.expo.modules.camera.tasks.ResolveTakenPictureAsyncTask.doInBackground(ResolveTakenPictureAsyncTask.java:1) at android.os.AsyncTask$3.call(AsyncTask.java:378) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:919)
Expected Behavior vs Actual Behavior
Picture should be taken and stored. It was working on Expo 36 before upgrade to 39
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (1 by maintainers)
My camera causes my app to crash on SDK 43 in EAS on a physical Android device. Any thoughts?
Same here… The app crashes as soon as it encounters the screen embedding the camera component and i’m not getting any logs either