question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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:closed
  • Created 3 years ago
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

6reactions
ShyGuy189540commented, Dec 22, 2021

My camera causes my app to crash on SDK 43 in EAS on a physical Android device. Any thoughts?

1reaction
Sheharyar566commented, Apr 19, 2021

Same here… The app crashes as soon as it encounters the screen embedding the camera component and i’m not getting any logs either

Read more comments on GitHub >

github_iconTop Results From Across the Web

The emulator camera crashes when recording ... - Issue Tracker
Use Host GPU: Yes. After booting the system image on emulator, then start the Camera and click the button to record video. EXPECTED...
Read more >
Detect and diagnose crashes - Android Developers
The first step to fix a crash is to identify the place where it happens. You can use the stack trace available in...
Read more >
Android App Crashes after Taking photo on real device but ...
I have a camera intent that takes a photo then returns back to the activity. It works fine on the emulator but on...
Read more >
In android emulator, whenever I call camera.TakePicture , the ...
Hey everyone, I'm trying to make a basic app that uses the camera to take a picture and then display the picture taken....
Read more >
What to Do If the Camera App on Your Android Device Keeps ...
If your camera app manages to open but then crashes shortly after, you can try botting it into Safe Mode. What Safe Mode...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found