Reputation: 257
I'm trying to make a react-native project where i can enter the camera on the native side by clicking on a button on the react side.
it needs to click a single pic and send the path of file back to react Everything works fine. the file is being saved (1600X1200 resolution) but its not returning to react side and an error is coming i.e.:-
2019-05-30 15:32:49.497 28080-28132/com.gjcamera E/BufferItemConsumer:
[ImageReader-1600x1200f100m1-28080-0] Failed to release buffer: Unknown error -1 (1).
I don't know where i am making a mistake.
here's my code:-
App.js:-
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, TouchableOpacity, NativeModules } from 'react-native';
const GJC = NativeModules.GJCamera;
type Props = {};
export default class App extends Component<Props> {
constructor() {
super();
this.state = {
imagePathh: "empty",
}
this.OpenMyCamera = this.OpenMyCamera.bind();
}
OpenMyCamera = async () => {
const result = await GJC.openCamera();
this.setState({ imagePathh: result });
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To enter camera, click on the "Camera" below</Text>
<Text style={styles.instructions}>The path of image will be shown below...</Text>
<TouchableOpacity style={{ backgroundColor: 'green' }} onPress={() => this.OpenMyCamera()}>
<Text style={{ color: '#fff' }}>Camera</Text>
</TouchableOpacity>
<Text style={{ paddingTop: 300 }}>The Path of image is </Text>
<Text style={{ color: "skyblue" }}>{this.state.imagePathh}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
GJCameraModule.java:-
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.widget.Toast;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.HashMap;
import java.util.Map;
import static android.support.v4.content.ContextCompat.startActivity;
public class GJCameraModule extends ReactContextBaseJavaModule {
private Promise promise;
public GJCameraModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@ReactMethod
public String show() {
String imagePath = "";
String imageName = "";
imageName = "";//GJCamera.sendPath();
imagePath = Environment.getExternalStorageDirectory() + "/DCIM/Camera/" + imageName + ".jpg";
return imagePath.toString();
}
@ReactMethod
public void openCamera(final Promise promise) {
Toast.makeText(getReactApplicationContext(), "LOLZ", Toast.LENGTH_SHORT).show();
try {
GJCamera gjc = GJCamera.newInstance();
gjc.setPromise(promise);
Intent intent = new Intent(getCurrentActivity(), GJCamera.class);
getCurrentActivity().startActivity(intent);
Toast.makeText(getReactApplicationContext(), "LOLZ--Return", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
promise.reject(e.getMessage(), e.getMessage());
}
}
@Override
public String getName() {
return "GJCamera";
}
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
String android_id = Settings.System.getString(getReactApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
constants.put("uniqueId", android_id);
return constants;
}
}
GJCamera.java:-
package com.gjcamera;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableMap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
public class GJCamera extends AppCompatActivity {
private ImageButton btnCapture;
private TextureView textureView;
public static String imgName;
private static Promise promise;
//Check state orientation of output image
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private String cameraId;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSessions;
private CaptureRequest.Builder captureRequestBuilder;
private Size imageDimension;
private ImageReader imageReader;
//Save to FILE
private File file;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private boolean mFlashSupported;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
SurfaceTexture texture;
public static GJCamera newInstance() {
GJCamera a = new GJCamera();
return a;
}
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
createCameraPreview();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
// if (promise!=null) { promise.reject("Error");}
// promise = null;
cameraDevice = camera;
returnHome();
}
@Override
public void onError(@NonNull CameraDevice camera, int i) {
// if (promise!=null) { promise.reject("Error");}
// promise = null;
cameraDevice = camera;
returnHome();
}
};
public void setPromise(Promise promise) {
this.promise = promise;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gjcamera);
textureView = findViewById(R.id.textureView);
//From Java 1.4 , you can use keyword 'assert' to check expression true or false
assert textureView != null;
textureView.setSurfaceTextureListener(textureListener);
btnCapture = findViewById(R.id.clickButton);
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
takePicture();
}
});
}
private void takePicture() {
if (cameraDevice == null)
return;
CameraManager manager = null;
manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null)
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(ImageFormat.JPEG);
//Capture image with custom size
int width = 1600;
int height = 1200;
imageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurface = new ArrayList<>(2);
outputSurface.add(imageReader.getSurface());
outputSurface.add(new Surface(textureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(imageReader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
//Check orientation base on device
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
file = new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera/IMG_" + calendar.get(Calendar.YEAR) + calendar.get(Calendar.MONTH) + calendar.get(Calendar.DATE) + "_" + calendar.get(Calendar.HOUR_OF_DAY) + calendar.get(Calendar.MINUTE) + calendar.get(Calendar.SECOND) + ".jpg");
ImageReader.OnImageAvailableListener readerListener = null;
readerListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReadr) {
Image image = null;
try {
image = imageReader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
{
if (image != null)
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
} finally {
if (outputStream != null)
outputStream.close();
}
}
};
imageReader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(GJCamera.this, "Saved " + file, Toast.LENGTH_SHORT).show();
returnHome();
}
};
cameraDevice.createCaptureSession(outputSurface, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
try {
cameraCaptureSession.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
// cameraDevice.close();
//convertFileToWritableMap(file));
// promise = null;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void returnHome() {
texture.release();
// if(imageReader != null) {
// imageReader.close();
// imageReader = null;
// }
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
if (cameraCaptureSessions != null) {
cameraCaptureSessions.close();
cameraCaptureSessions = null;
}
if (promise != null) {
promise.resolve(convertFileToWritableMap(file));
promise = null;
}
}
private void createCameraPreview() {
try {
texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(1600, 1200);
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
if (cameraDevice == null)
return;
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(GJCamera.this, "Changed", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void updatePreview() {
if (cameraDevice == null)
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
//Check realtime permission if run higher API 23
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CAMERA_PERMISSION);
return;
}
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
openCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "You can't use camera without permission", Toast.LENGTH_SHORT).show();
finish();
}
}
}
@Override
protected void onResume() {
super.onResume();
startBackgroundThread();
if (textureView.isAvailable())
openCamera();
else
textureView.setSurfaceTextureListener(textureListener);
}
@Override
protected void onPause() {
stopBackgroundThread();
super.onPause();
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("Camera Background");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
public static WritableMap convertFileToWritableMap(File fileLocation) {
WritableMap newFile = Arguments.createMap();
if (fileLocation == null) return newFile;
newFile.putString("imgPath", fileLocation.getPath());
return newFile;
}
}
activity_gjcamera.xml:-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gjcamera.MainActivity">
<TextureView
android:id="@+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/clickButton"
/>
<ImageButton
android:id="@+id/clickButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:src="@drawable/camera_click" />
</RelativeLayout>
BTW, Thanks for the help.
Upvotes: 0
Views: 2327
Reputation: 257
finally, found it:- in GJCamera.java within returnHome() Method:-
if (promise != null) {
promise.resolve(convertFileToWritableMap(file));
promise = null;
}
change it to:-
if (promise != null) {
promise.resolve(convertFileToWritableMap(file));
promise = null;
finish(); // in order to finish the activity.
}
The entire project is present Here.
Upvotes: 1