275 lines
11 KiB
Java
275 lines
11 KiB
Java
/**
|
|
* Created by Fabrice Armisen (farmisen@gmail.com) on 1/4/16.
|
|
*/
|
|
|
|
package com.lwansbrough.RCTCamera;
|
|
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.BitmapFactory;
|
|
import android.hardware.Camera;
|
|
import android.net.Uri;
|
|
import android.os.Environment;
|
|
import android.provider.MediaStore;
|
|
import android.util.Base64;
|
|
import android.util.Log;
|
|
import com.facebook.react.bridge.*;
|
|
|
|
import javax.annotation.Nullable;
|
|
import java.io.*;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
public class RCTCameraModule extends ReactContextBaseJavaModule {
|
|
private static final String TAG = "RCTCameraModule";
|
|
|
|
public static final int RCT_CAMERA_ASPECT_FILL = 0;
|
|
public static final int RCT_CAMERA_ASPECT_FIT = 1;
|
|
public static final int RCT_CAMERA_ASPECT_STRETCH = 2;
|
|
public static final int RCT_CAMERA_CAPTURE_MODE_STILL = 0;
|
|
public static final int RCT_CAMERA_CAPTURE_MODE_VIDEO = 1;
|
|
public static final int RCT_CAMERA_CAPTURE_TARGET_MEMORY = 0;
|
|
public static final int RCT_CAMERA_CAPTURE_TARGET_DISK = 1;
|
|
public static final int RCT_CAMERA_CAPTURE_TARGET_CAMERA_ROLL = 2;
|
|
public static final int RCT_CAMERA_CAPTURE_TARGET_TEMP = 3;
|
|
public static final int RCT_CAMERA_ORIENTATION_AUTO = 0;
|
|
public static final int RCT_CAMERA_ORIENTATION_LANDSCAPE_LEFT = 1;
|
|
public static final int RCT_CAMERA_ORIENTATION_LANDSCAPE_RIGHT = 2;
|
|
public static final int RCT_CAMERA_ORIENTATION_PORTRAIT = 3;
|
|
public static final int RCT_CAMERA_ORIENTATION_PORTRAIT_UPSIDE_DOWN = 4;
|
|
public static final int RCT_CAMERA_TYPE_FRONT = 1;
|
|
public static final int RCT_CAMERA_TYPE_BACK = 2;
|
|
public static final int RCT_CAMERA_FLASH_MODE_OFF = 0;
|
|
public static final int RCT_CAMERA_FLASH_MODE_ON = 1;
|
|
public static final int RCT_CAMERA_FLASH_MODE_AUTO = 2;
|
|
public static final int RCT_CAMERA_TORCH_MODE_OFF = 0;
|
|
public static final int RCT_CAMERA_TORCH_MODE_ON = 1;
|
|
public static final int RCT_CAMERA_TORCH_MODE_AUTO = 2;
|
|
public static final int MEDIA_TYPE_IMAGE = 1;
|
|
public static final int MEDIA_TYPE_VIDEO = 2;
|
|
|
|
private final ReactApplicationContext _reactContext;
|
|
|
|
public RCTCameraModule(ReactApplicationContext reactContext) {
|
|
super(reactContext);
|
|
_reactContext = reactContext;
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return "RCTCameraModule";
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public Map<String, Object> getConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("Aspect", getAspectConstants());
|
|
put("Type", getTypeConstants());
|
|
put("CaptureMode", getCaptureModeConstants());
|
|
put("CaptureTarget", getCaptureTargetConstants());
|
|
put("Orientation", getOrientationConstants());
|
|
put("FlashMode", getFlashModeConstants());
|
|
put("TorchMode", getTorchModeConstants());
|
|
}
|
|
|
|
private Map<String, Object> getAspectConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("stretch", RCT_CAMERA_ASPECT_STRETCH);
|
|
put("fit", RCT_CAMERA_ASPECT_FIT);
|
|
put("fill", RCT_CAMERA_ASPECT_FILL);
|
|
}
|
|
});
|
|
}
|
|
|
|
private Map<String, Object> getTypeConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("front", RCT_CAMERA_TYPE_FRONT);
|
|
put("back", RCT_CAMERA_TYPE_BACK);
|
|
}
|
|
});
|
|
}
|
|
|
|
private Map<String, Object> getCaptureModeConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("still", RCT_CAMERA_CAPTURE_MODE_STILL);
|
|
put("video", RCT_CAMERA_CAPTURE_MODE_VIDEO);
|
|
}
|
|
});
|
|
}
|
|
|
|
private Map<String, Object> getCaptureTargetConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("memory", RCT_CAMERA_CAPTURE_TARGET_MEMORY);
|
|
put("disk", RCT_CAMERA_CAPTURE_TARGET_DISK);
|
|
put("cameraRoll", RCT_CAMERA_CAPTURE_TARGET_CAMERA_ROLL);
|
|
put("temp", RCT_CAMERA_CAPTURE_TARGET_TEMP);
|
|
}
|
|
});
|
|
}
|
|
|
|
private Map<String, Object> getOrientationConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("auto", RCT_CAMERA_ORIENTATION_AUTO);
|
|
put("landscapeLeft", RCT_CAMERA_ORIENTATION_LANDSCAPE_LEFT);
|
|
put("landscapeRight", RCT_CAMERA_ORIENTATION_LANDSCAPE_RIGHT);
|
|
put("portrait", RCT_CAMERA_ORIENTATION_PORTRAIT);
|
|
put("portraitUpsideDown", RCT_CAMERA_ORIENTATION_PORTRAIT_UPSIDE_DOWN);
|
|
}
|
|
});
|
|
}
|
|
|
|
private Map<String, Object> getFlashModeConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("off", RCT_CAMERA_FLASH_MODE_OFF);
|
|
put("on", RCT_CAMERA_FLASH_MODE_ON);
|
|
put("auto", RCT_CAMERA_FLASH_MODE_AUTO);
|
|
}
|
|
});
|
|
}
|
|
|
|
private Map<String, Object> getTorchModeConstants() {
|
|
return Collections.unmodifiableMap(new HashMap<String, Object>() {
|
|
{
|
|
put("off", RCT_CAMERA_TORCH_MODE_OFF);
|
|
put("on", RCT_CAMERA_TORCH_MODE_ON);
|
|
put("auto", RCT_CAMERA_TORCH_MODE_AUTO);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
@ReactMethod
|
|
public void capture(final ReadableMap options, final Callback callback) {
|
|
Camera camera = RCTCamera.getInstance().acquireCameraInstance(options.getInt("type"));
|
|
if (null == camera) {
|
|
callback.invoke("No camera found.", null);
|
|
return;
|
|
}
|
|
camera.takePicture(null, null, new Camera.PictureCallback() {
|
|
@Override
|
|
public void onPictureTaken(byte[] data, Camera camera) {
|
|
camera.stopPreview();
|
|
camera.startPreview();
|
|
switch (options.getInt("target")) {
|
|
case RCT_CAMERA_CAPTURE_TARGET_MEMORY:
|
|
String encoded = Base64.encodeToString(data, Base64.DEFAULT);
|
|
callback.invoke(null, encoded);
|
|
break;
|
|
case RCT_CAMERA_CAPTURE_TARGET_CAMERA_ROLL:
|
|
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
|
|
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, bitmapOptions);
|
|
String url = MediaStore.Images.Media.insertImage(
|
|
_reactContext.getContentResolver(),
|
|
bitmap, options.getString("title"),
|
|
options.getString("description"));
|
|
callback.invoke(null, url);
|
|
break;
|
|
case RCT_CAMERA_CAPTURE_TARGET_DISK:
|
|
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
|
|
if (pictureFile == null) {
|
|
callback.invoke("Error creating media file.", null);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
FileOutputStream fos = new FileOutputStream(pictureFile);
|
|
fos.write(data);
|
|
fos.close();
|
|
} catch (FileNotFoundException e) {
|
|
callback.invoke("File not found: " + e.getMessage(), null);
|
|
} catch (IOException e) {
|
|
callback.invoke("Error accessing file: " + e.getMessage(), null);
|
|
}
|
|
callback.invoke(null, Uri.fromFile(pictureFile).toString());
|
|
break;
|
|
case RCT_CAMERA_CAPTURE_TARGET_TEMP:
|
|
File tempFile = getTempMediaFile(MEDIA_TYPE_IMAGE);
|
|
|
|
if (tempFile == null) {
|
|
callback.invoke("Error creating media file.", null);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
FileOutputStream fos = new FileOutputStream(tempFile);
|
|
fos.write(data);
|
|
fos.close();
|
|
} catch (FileNotFoundException e) {
|
|
callback.invoke("File not found: " + e.getMessage(), null);
|
|
} catch (IOException e) {
|
|
callback.invoke("Error accessing file: " + e.getMessage(), null);
|
|
}
|
|
callback.invoke(null, Uri.fromFile(tempFile).toString());
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@ReactMethod
|
|
public void stopCapture(final ReadableMap options, final Callback callback) {
|
|
// TODO: implement video capture
|
|
}
|
|
|
|
private File getOutputMediaFile(int type) {
|
|
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
|
|
Environment.DIRECTORY_PICTURES), "RCTCameraModule");
|
|
|
|
// Create the storage directory if it does not exist
|
|
if (!mediaStorageDir.exists()) {
|
|
if (!mediaStorageDir.mkdirs()) {
|
|
Log.e(TAG, "failed to create directory:" + mediaStorageDir.getAbsolutePath());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Create a media file name
|
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
File mediaFile;
|
|
if (type == MEDIA_TYPE_IMAGE) {
|
|
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
|
|
"IMG_" + timeStamp + ".jpg");
|
|
} else if (type == MEDIA_TYPE_VIDEO) {
|
|
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
|
|
"VID_" + timeStamp + ".mp4");
|
|
} else {
|
|
Log.e(TAG, "Unsupported media type:" + type);
|
|
return null;
|
|
}
|
|
return mediaFile;
|
|
}
|
|
|
|
|
|
private File getTempMediaFile(int type) {
|
|
try {
|
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
File outputDir = _reactContext.getCacheDir();
|
|
File outputFile;
|
|
|
|
if (type == MEDIA_TYPE_IMAGE) {
|
|
outputFile = File.createTempFile("IMG_" + timeStamp, ".jpg", outputDir);
|
|
} else if (type == MEDIA_TYPE_VIDEO) {
|
|
outputFile = File.createTempFile("VID_" + timeStamp, ".mp4", outputDir);
|
|
} else {
|
|
Log.e(TAG, "Unsupported media type:" + type);
|
|
return null;
|
|
}
|
|
return outputFile;
|
|
} catch (Exception e) {
|
|
Log.e(TAG, e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
}
|