feat(android): Support to enumerate and select Camera devices (#2492)
* Android only: Support to enumerate Camera devices and to select from one of them. * No need to have the camera in running state if querying for IDs. * Silly bug, not using string compare. Also, do not run any camera code if the actual camera doesn't change. * Crash fix when focus coordinates are set to null/undefined not being handled. Notes about not supported flash/focus * If a camera is not found, set the first available camera just like Camera2 does. * missing semicolon * Fixes to Camera2 API: - First change is related to camera selection by ID. Some more code was required to correctly set the facing flag and characteristics - Second change fixes a previous issue (unrelated to the PR) that was causing the preview of the camera to look upside down on rotated devices. Device rotation should not affect the display (nor set it). Device rotation should however be used for the final image (and not screen rotation). Some code was borrowed from Camera1.
This commit is contained in:
parent
200c7e136c
commit
612cb65f2a
@ -34,6 +34,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -73,6 +75,7 @@ class Camera1 extends CameraViewImpl implements MediaRecorder.OnInfoListener,
|
||||
private Handler mHandler = new Handler();
|
||||
|
||||
private int mCameraId;
|
||||
private String _mCameraId;
|
||||
|
||||
private final AtomicBoolean isPictureCaptureInProgress = new AtomicBoolean(false);
|
||||
|
||||
@ -281,6 +284,31 @@ class Camera1 extends CameraViewImpl implements MediaRecorder.OnInfoListener,
|
||||
return mFacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
void setCameraId(String id) {
|
||||
|
||||
if(!Objects.equals(_mCameraId, id)){
|
||||
_mCameraId = id;
|
||||
|
||||
// only update if our camera ID actually changes
|
||||
// from what we currently have.
|
||||
// Passing null will always yield true
|
||||
if(!Objects.equals(_mCameraId, String.valueOf(mCameraId))){
|
||||
// this will call chooseCamera
|
||||
if (isCameraOpened()) {
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCameraId() {
|
||||
return _mCameraId;
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<AspectRatio> getSupportedAspectRatios() {
|
||||
SizeMap idealAspectRatios = mPreviewSizes;
|
||||
@ -292,6 +320,23 @@ class Camera1 extends CameraViewImpl implements MediaRecorder.OnInfoListener,
|
||||
return idealAspectRatios.ratios();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
List<Properties> getCameraIds() {
|
||||
List<Properties> ids = new ArrayList<>();
|
||||
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
|
||||
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
|
||||
Properties p = new Properties();
|
||||
Camera.getCameraInfo(i, info);
|
||||
p.put("id", String.valueOf(i));
|
||||
p.put("type", String.valueOf(info.facing));
|
||||
ids.add(p);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
SortedSet<Size> getAvailablePictureSizes(AspectRatio ratio) {
|
||||
return mPictureSizes.sizes(ratio);
|
||||
@ -446,6 +491,7 @@ class Camera1 extends CameraViewImpl implements MediaRecorder.OnInfoListener,
|
||||
return mZoom;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setWhiteBalance(int whiteBalance) {
|
||||
if (whiteBalance == mWhiteBalance) {
|
||||
@ -693,14 +739,32 @@ class Camera1 extends CameraViewImpl implements MediaRecorder.OnInfoListener,
|
||||
* This rewrites {@link #mCameraId} and {@link #mCameraInfo}.
|
||||
*/
|
||||
private void chooseCamera() {
|
||||
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
|
||||
Camera.getCameraInfo(i, mCameraInfo);
|
||||
if (mCameraInfo.facing == mFacing) {
|
||||
mCameraId = i;
|
||||
return;
|
||||
if(_mCameraId == null){
|
||||
int count = Camera.getNumberOfCameras();
|
||||
if(count == 0){
|
||||
throw new RuntimeException("No camera available.");
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Camera.getCameraInfo(i, mCameraInfo);
|
||||
if (mCameraInfo.facing == mFacing) {
|
||||
mCameraId = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// no camera found, set the one we have
|
||||
mCameraId = 0;
|
||||
Camera.getCameraInfo(mCameraId, mCameraInfo);
|
||||
}
|
||||
else{
|
||||
try{
|
||||
mCameraId = Integer.parseInt(_mCameraId);
|
||||
Camera.getCameraInfo(mCameraId, mCameraInfo);
|
||||
}
|
||||
catch(Exception e){
|
||||
mCameraId = INVALID_CAMERA_ID;
|
||||
}
|
||||
}
|
||||
mCameraId = INVALID_CAMERA_ID;
|
||||
}
|
||||
|
||||
private boolean openCamera() {
|
||||
|
||||
@ -50,7 +50,11 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
@ -199,6 +203,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
|
||||
|
||||
|
||||
private String mCameraId;
|
||||
private String _mCameraId;
|
||||
|
||||
private CameraCharacteristics mCameraCharacteristics;
|
||||
|
||||
@ -359,11 +364,58 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
|
||||
return mFacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
void setCameraId(String id) {
|
||||
if(!Objects.equals(_mCameraId, id)){
|
||||
_mCameraId = id;
|
||||
|
||||
// only update if our camera ID actually changes
|
||||
// from what we currently have.
|
||||
// Passing null will always yield true
|
||||
if(!Objects.equals(_mCameraId, mCameraId)){
|
||||
// this will call chooseCameraIdByFacing
|
||||
if (isCameraOpened()) {
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCameraId() {
|
||||
return _mCameraId;
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<AspectRatio> getSupportedAspectRatios() {
|
||||
return mPreviewSizes.ratios();
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Properties> getCameraIds() {
|
||||
try{
|
||||
|
||||
List<Properties> ids = new ArrayList<>();
|
||||
|
||||
String[] cameraIds = mCameraManager.getCameraIdList();
|
||||
for (String id : cameraIds) {
|
||||
Properties p = new Properties();
|
||||
|
||||
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
|
||||
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
|
||||
|
||||
p.put("id", id);
|
||||
p.put("type", String.valueOf(internal == CameraCharacteristics.LENS_FACING_FRONT ? Constants.FACING_FRONT : Constants.FACING_BACK));
|
||||
ids.add(p);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
catch (CameraAccessException e) {
|
||||
throw new RuntimeException("Failed to get a list of camera ids", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
SortedSet<Size> getAvailablePictureSizes(AspectRatio ratio) {
|
||||
return mPictureSizes.sizes(ratio);
|
||||
@ -651,7 +703,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
|
||||
@Override
|
||||
void setDeviceOrientation(int deviceOrientation) {
|
||||
mDeviceOrientation = deviceOrientation;
|
||||
mPreview.setDisplayOrientation(mDeviceOrientation);
|
||||
//mPreview.setDisplayOrientation(deviceOrientation); // this is not needed and messes up the display orientation
|
||||
}
|
||||
|
||||
/**
|
||||
@ -660,55 +712,90 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
|
||||
* {@link #mFacing}.</p>
|
||||
*/
|
||||
private boolean chooseCameraIdByFacing() {
|
||||
try {
|
||||
int internalFacing = INTERNAL_FACINGS.get(mFacing);
|
||||
final String[] ids = mCameraManager.getCameraIdList();
|
||||
if (ids.length == 0) { // No camera
|
||||
throw new RuntimeException("No camera available.");
|
||||
}
|
||||
for (String id : ids) {
|
||||
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
|
||||
Integer level = characteristics.get(
|
||||
if(_mCameraId == null){
|
||||
try {
|
||||
int internalFacing = INTERNAL_FACINGS.get(mFacing);
|
||||
final String[] ids = mCameraManager.getCameraIdList();
|
||||
if (ids.length == 0) { // No camera
|
||||
throw new RuntimeException("No camera available.");
|
||||
}
|
||||
for (String id : ids) {
|
||||
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
|
||||
Integer level = characteristics.get(
|
||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
|
||||
if (level == null ||
|
||||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
|
||||
continue;
|
||||
}
|
||||
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
|
||||
if (internal == null) {
|
||||
throw new NullPointerException("Unexpected state: LENS_FACING null");
|
||||
}
|
||||
if (internal == internalFacing) {
|
||||
mCameraId = id;
|
||||
mCameraCharacteristics = characteristics;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Not found
|
||||
mCameraId = ids[0];
|
||||
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
|
||||
Integer level = mCameraCharacteristics.get(
|
||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
|
||||
if (level == null ||
|
||||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
|
||||
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
|
||||
if (internal == null) {
|
||||
throw new NullPointerException("Unexpected state: LENS_FACING null");
|
||||
}
|
||||
if (internal == internalFacing) {
|
||||
mCameraId = id;
|
||||
mCameraCharacteristics = characteristics;
|
||||
return true;
|
||||
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
|
||||
if (INTERNAL_FACINGS.valueAt(i) == internal) {
|
||||
mFacing = INTERNAL_FACINGS.keyAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// The operation can reach here when the only camera device is an external one.
|
||||
// We treat it as facing back.
|
||||
mFacing = Constants.FACING_BACK;
|
||||
return true;
|
||||
} catch (CameraAccessException e) {
|
||||
throw new RuntimeException("Failed to get a list of camera devices", e);
|
||||
}
|
||||
// Not found
|
||||
mCameraId = ids[0];
|
||||
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
|
||||
Integer level = mCameraCharacteristics.get(
|
||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
|
||||
if (level == null ||
|
||||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
|
||||
return false;
|
||||
}
|
||||
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
|
||||
if (internal == null) {
|
||||
throw new NullPointerException("Unexpected state: LENS_FACING null");
|
||||
}
|
||||
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
|
||||
if (INTERNAL_FACINGS.valueAt(i) == internal) {
|
||||
mFacing = INTERNAL_FACINGS.keyAt(i);
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
|
||||
try{
|
||||
// need to set the mCameraCharacteristics variable as above and also do the same checks
|
||||
// for legacy hardware
|
||||
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(_mCameraId);
|
||||
|
||||
Integer level = mCameraCharacteristics.get(
|
||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
|
||||
if (level == null ||
|
||||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// set our facing variable so orientation also works as expected
|
||||
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
|
||||
if (internal == null) {
|
||||
throw new NullPointerException("Unexpected state: LENS_FACING null");
|
||||
}
|
||||
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
|
||||
if (INTERNAL_FACINGS.valueAt(i) == internal) {
|
||||
mFacing = INTERNAL_FACINGS.keyAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mCameraId = _mCameraId;
|
||||
return true;
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Failed to get camera characteristics", e);
|
||||
}
|
||||
// The operation can reach here when the only camera device is an external one.
|
||||
// We treat it as facing back.
|
||||
mFacing = Constants.FACING_BACK;
|
||||
return true;
|
||||
} catch (CameraAccessException e) {
|
||||
throw new RuntimeException("Failed to get a list of camera devices", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1190,9 +1277,25 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
|
||||
private int getOutputRotation() {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
int sensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
|
||||
return (sensorOrientation +
|
||||
mDisplayOrientation * (mFacing == Constants.FACING_FRONT ? 1 : -1) +
|
||||
360) % 360;
|
||||
|
||||
// updated and copied from Camera1
|
||||
if (mFacing == Constants.FACING_BACK) {
|
||||
return (sensorOrientation + mDeviceOrientation) % 360;
|
||||
} else {
|
||||
final int landscapeFlip = isLandscape(mDeviceOrientation) ? 180 : 0;
|
||||
return (sensorOrientation + mDeviceOrientation + landscapeFlip) % 360;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the supplied orientation is in landscape.
|
||||
*
|
||||
* @param orientationDegrees Orientation in degrees (0,90,180,270)
|
||||
* @return True if in landscape, false if portrait
|
||||
*/
|
||||
private boolean isLandscape(int orientationDegrees) {
|
||||
return (orientationDegrees == Constants.LANDSCAPE_90 ||
|
||||
orientationDegrees == Constants.LANDSCAPE_270);
|
||||
}
|
||||
|
||||
private void setUpMediaRecorder(String path, int maxDuration, int maxFileSize, boolean recordAudio, CamcorderProfile profile) {
|
||||
|
||||
@ -41,6 +41,8 @@ import com.facebook.react.bridge.ReadableMap;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
@ -220,6 +222,7 @@ public class CameraView extends FrameLayout {
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
SavedState state = new SavedState(super.onSaveInstanceState());
|
||||
state.facing = getFacing();
|
||||
state.cameraId = getCameraId();
|
||||
state.ratio = getAspectRatio();
|
||||
state.autoFocus = getAutoFocus();
|
||||
state.flash = getFlash();
|
||||
@ -241,6 +244,7 @@ public class CameraView extends FrameLayout {
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
setFacing(ss.facing);
|
||||
setCameraId(ss.cameraId);
|
||||
setAspectRatio(ss.ratio);
|
||||
setAutoFocus(ss.autoFocus);
|
||||
setFlash(ss.flash);
|
||||
@ -384,6 +388,24 @@ public class CameraView extends FrameLayout {
|
||||
return mImpl.getFacing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Chooses camera by its camera iD
|
||||
*
|
||||
* @param id The camera ID
|
||||
*/
|
||||
public void setCameraId(String id) {
|
||||
mImpl.setCameraId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently set camera ID
|
||||
*
|
||||
* @return The camera facing.
|
||||
*/
|
||||
public String getCameraId() {
|
||||
return mImpl.getCameraId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the aspect ratios supported by the current camera.
|
||||
*/
|
||||
@ -391,6 +413,13 @@ public class CameraView extends FrameLayout {
|
||||
return mImpl.getSupportedAspectRatios();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the camera IDs supported by the phone as a String
|
||||
*/
|
||||
public List<Properties> getCameraIds() {
|
||||
return mImpl.getCameraIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aspect ratio of camera.
|
||||
*
|
||||
@ -411,7 +440,7 @@ public class CameraView extends FrameLayout {
|
||||
public AspectRatio getAspectRatio() {
|
||||
return mImpl.getAspectRatio();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets all the picture sizes for particular ratio supported by the current camera.
|
||||
*
|
||||
@ -420,7 +449,7 @@ public class CameraView extends FrameLayout {
|
||||
public SortedSet<Size> getAvailablePictureSizes(@NonNull AspectRatio ratio) {
|
||||
return mImpl.getAvailablePictureSizes(ratio);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the size of taken pictures.
|
||||
*
|
||||
@ -429,7 +458,7 @@ public class CameraView extends FrameLayout {
|
||||
public void setPictureSize(@NonNull Size size) {
|
||||
mImpl.setPictureSize(size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the size of pictures that will be taken.
|
||||
*/
|
||||
@ -495,7 +524,7 @@ public class CameraView extends FrameLayout {
|
||||
public int getCameraOrientation() {
|
||||
return mImpl.getCameraOrientation();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the auto focus point.
|
||||
*
|
||||
@ -556,11 +585,11 @@ public class CameraView extends FrameLayout {
|
||||
public void stopRecording() {
|
||||
mImpl.stopRecording();
|
||||
}
|
||||
|
||||
|
||||
public void resumePreview() {
|
||||
mImpl.resumePreview();
|
||||
}
|
||||
|
||||
|
||||
public void pausePreview() {
|
||||
mImpl.pausePreview();
|
||||
}
|
||||
@ -646,6 +675,8 @@ public class CameraView extends FrameLayout {
|
||||
@Facing
|
||||
int facing;
|
||||
|
||||
String cameraId;
|
||||
|
||||
AspectRatio ratio;
|
||||
|
||||
boolean autoFocus;
|
||||
@ -662,13 +693,14 @@ public class CameraView extends FrameLayout {
|
||||
int whiteBalance;
|
||||
|
||||
boolean scanning;
|
||||
|
||||
|
||||
Size pictureSize;
|
||||
|
||||
@SuppressWarnings("WrongConstant")
|
||||
public SavedState(Parcel source, ClassLoader loader) {
|
||||
super(source);
|
||||
facing = source.readInt();
|
||||
cameraId = source.readString();
|
||||
ratio = source.readParcelable(loader);
|
||||
autoFocus = source.readByte() != 0;
|
||||
flash = source.readInt();
|
||||
@ -688,6 +720,7 @@ public class CameraView extends FrameLayout {
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeInt(facing);
|
||||
out.writeString(cameraId);
|
||||
out.writeParcelable(ratio, 0);
|
||||
out.writeByte((byte) (autoFocus ? 1 : 0));
|
||||
out.writeInt(flash);
|
||||
|
||||
@ -22,9 +22,12 @@ import android.graphics.SurfaceTexture;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
|
||||
abstract class CameraViewImpl {
|
||||
|
||||
protected final Callback mCallback;
|
||||
@ -53,12 +56,18 @@ abstract class CameraViewImpl {
|
||||
|
||||
abstract int getFacing();
|
||||
|
||||
abstract void setCameraId(String id);
|
||||
|
||||
abstract String getCameraId();
|
||||
|
||||
abstract Set<AspectRatio> getSupportedAspectRatios();
|
||||
|
||||
|
||||
abstract List<Properties> getCameraIds();
|
||||
|
||||
abstract SortedSet<Size> getAvailablePictureSizes(AspectRatio ratio);
|
||||
|
||||
|
||||
abstract void setPictureSize(Size size);
|
||||
|
||||
|
||||
abstract Size getPictureSize();
|
||||
|
||||
/**
|
||||
@ -92,7 +101,7 @@ abstract class CameraViewImpl {
|
||||
abstract void setDisplayOrientation(int displayOrientation);
|
||||
|
||||
abstract void setDeviceOrientation(int deviceOrientation);
|
||||
|
||||
|
||||
abstract void setFocusArea(float x, float y);
|
||||
|
||||
abstract void setFocusDepth(float value);
|
||||
@ -110,9 +119,9 @@ abstract class CameraViewImpl {
|
||||
abstract void setScanning(boolean isScanning);
|
||||
|
||||
abstract boolean getScanning();
|
||||
|
||||
|
||||
abstract public void resumePreview();
|
||||
|
||||
|
||||
abstract public void pausePreview();
|
||||
|
||||
abstract public void setPreviewTexture(SurfaceTexture surfaceTexture);
|
||||
|
||||
@ -21,11 +21,14 @@ import com.google.android.cameraview.Size;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
|
||||
public class CameraModule extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "CameraModule";
|
||||
|
||||
@ -349,49 +352,77 @@ public class CameraModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
});
|
||||
}
|
||||
@ReactMethod
|
||||
public void getAvailablePictureSizes(final String ratio, final int viewTag, final Promise promise) {
|
||||
final ReactApplicationContext context = getReactApplicationContext();
|
||||
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
final RNCameraView cameraView;
|
||||
|
||||
try {
|
||||
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
|
||||
WritableArray result = Arguments.createArray();
|
||||
if (cameraView.isCameraOpened()) {
|
||||
SortedSet<Size> sizes = cameraView.getAvailablePictureSizes(AspectRatio.parse(ratio));
|
||||
for (Size size : sizes) {
|
||||
result.pushString(size.toString());
|
||||
}
|
||||
promise.resolve(result);
|
||||
} else {
|
||||
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
promise.reject("E_CAMERA_BAD_VIEWTAG", "getAvailablePictureSizesAsync: Expected a Camera component");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ReactMethod
|
||||
public void getCameraIds(final int viewTag, final Promise promise) {
|
||||
final ReactApplicationContext context = getReactApplicationContext();
|
||||
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
final RNCameraView cameraView;
|
||||
try {
|
||||
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
|
||||
WritableArray result = Arguments.createArray();
|
||||
List<Properties> ids = cameraView.getCameraIds();
|
||||
for (Properties p : ids) {
|
||||
WritableMap m = new WritableNativeMap();
|
||||
m.putString("id", p.getProperty("id"));
|
||||
m.putInt("type", Integer.valueOf(p.getProperty("type")));
|
||||
result.pushMap(m);
|
||||
}
|
||||
promise.resolve(result);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
promise.reject("E_CAMERA_FAILED", e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void checkIfRecordAudioPermissionsAreDefined(final Promise promise) {
|
||||
try {
|
||||
PackageInfo info = getCurrentActivity().getPackageManager().getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
|
||||
if (info.requestedPermissions != null) {
|
||||
for (String p : info.requestedPermissions) {
|
||||
if (p.equals(Manifest.permission.RECORD_AUDIO)) {
|
||||
promise.resolve(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
promise.resolve(false);
|
||||
}
|
||||
@ReactMethod
|
||||
public void getAvailablePictureSizes(final String ratio, final int viewTag, final Promise promise) {
|
||||
final ReactApplicationContext context = getReactApplicationContext();
|
||||
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
final RNCameraView cameraView;
|
||||
|
||||
try {
|
||||
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
|
||||
WritableArray result = Arguments.createArray();
|
||||
if (cameraView.isCameraOpened()) {
|
||||
SortedSet<Size> sizes = cameraView.getAvailablePictureSizes(AspectRatio.parse(ratio));
|
||||
for (Size size : sizes) {
|
||||
result.pushString(size.toString());
|
||||
}
|
||||
promise.resolve(result);
|
||||
} else {
|
||||
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
promise.reject("E_CAMERA_BAD_VIEWTAG", "getAvailablePictureSizesAsync: Expected a Camera component");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void checkIfRecordAudioPermissionsAreDefined(final Promise promise) {
|
||||
try {
|
||||
PackageInfo info = getCurrentActivity().getPackageManager().getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
|
||||
if (info.requestedPermissions != null) {
|
||||
for (String p : info.requestedPermissions) {
|
||||
if (p.equals(Manifest.permission.RECORD_AUDIO)) {
|
||||
promise.resolve(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +73,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
|
||||
view.setFacing(type);
|
||||
}
|
||||
|
||||
@ReactProp(name = "cameraId")
|
||||
public void setCameraId(RNCameraView view, String id) {
|
||||
view.setCameraId(id);
|
||||
}
|
||||
|
||||
@ReactProp(name = "ratio")
|
||||
public void setRatio(RNCameraView view, String ratio) {
|
||||
view.setAspectRatio(AspectRatio.parse(ratio));
|
||||
@ -100,9 +105,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
|
||||
|
||||
@ReactProp(name = "autoFocusPointOfInterest")
|
||||
public void setAutoFocusPointOfInterest(RNCameraView view, ReadableMap coordinates) {
|
||||
float x = (float) coordinates.getDouble("x");
|
||||
float y = (float) coordinates.getDouble("y");
|
||||
view.setAutoFocusPointOfInterest(x, y);
|
||||
if(coordinates != null){
|
||||
float x = (float) coordinates.getDouble("x");
|
||||
float y = (float) coordinates.getDouble("y");
|
||||
view.setAutoFocusPointOfInterest(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "zoom")
|
||||
@ -171,7 +178,7 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
|
||||
public void setTracking(RNCameraView view, boolean trackingEnabled) {
|
||||
view.setTracking(trackingEnabled);
|
||||
}
|
||||
|
||||
|
||||
@ReactProp(name = "googleVisionBarcodeDetectorEnabled")
|
||||
public void setGoogleVisionBarcodeDetecting(RNCameraView view, boolean googleBarcodeDetectorEnabled) {
|
||||
view.setShouldGoogleDetectBarcodes(googleBarcodeDetectorEnabled);
|
||||
|
||||
@ -253,6 +253,14 @@ Values: `RNCamera.Constants.Type.front` or `RNCamera.Constants.Type.back` (defau
|
||||
|
||||
Use the `type` property to specify which camera to use.
|
||||
|
||||
### `Android` `cameraId`
|
||||
|
||||
Overrides the `type` property and uses the camera given by cameraId. Use `getCameraIds` to get the list of available IDs.
|
||||
|
||||
A common use case for this is to provide a "switch camera" button that loops through all available cameras.
|
||||
|
||||
Note: Variables such as flash might need to be resetted due to the camera not reporting an error when those values are not supported.
|
||||
|
||||
### `whiteBalance`
|
||||
|
||||
Values: `RNCamera.Constants.WhiteBalance.sunny`, `RNCamera.Constants.WhiteBalance.cloudy`, `RNCamera.Constants.WhiteBalance.shadow`, `RNCamera.Constants.WhiteBalance.incandescent`, `RNCamera.Constants.WhiteBalance.fluorescent` or `RNCamera.Constants.WhiteBalance.auto` (default)
|
||||
@ -596,7 +604,7 @@ The promise will be fulfilled with an object with some of the following properti
|
||||
|
||||
### `refreshAuthorizationStatus: Promise<void>`
|
||||
|
||||
Allows to make RNCamera check Permissions again and set status accordingly.
|
||||
Allows to make RNCamera check Permissions again and set status accordingly.
|
||||
Making it possible to refresh status of RNCamera after user initially rejected the permissions.
|
||||
|
||||
### `stopRecording: void`
|
||||
@ -615,6 +623,16 @@ Resumes the preview after pausePreview() has been called.
|
||||
|
||||
Android only. Returns a promise. The promise will be fulfilled with an object with an array containing strings with all camera aspect ratios supported by the device.
|
||||
|
||||
### `Android` `getCameraIdsAsync(): Promise`
|
||||
|
||||
Android only. Returns a promise. The promise will be fulfilled with an array containing objects with all camera IDs and type supported by the device.
|
||||
|
||||
The promise will be fulfilled with an array containing objects with some of the following properties:
|
||||
|
||||
- `id`: (string) the ID of the camera.
|
||||
|
||||
- `type`: One of `RNCamera.Constants.Type.front` | `RNCamera.Constants.Type.back`
|
||||
|
||||
### `iOS` `isRecording(): Promise<boolean>`
|
||||
|
||||
iOS only. Returns a promise. The promise will be fulfilled with a boolean indicating if currently recording is started or stopped.
|
||||
|
||||
@ -392,6 +392,7 @@ export default class Camera extends React.Component<PropsType, StateType> {
|
||||
googleVisionBarcodeType: PropTypes.number,
|
||||
googleVisionBarcodeMode: PropTypes.number,
|
||||
type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
cameraId: PropTypes.string,
|
||||
flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
exposure: PropTypes.number,
|
||||
whiteBalance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
@ -418,6 +419,7 @@ export default class Camera extends React.Component<PropsType, StateType> {
|
||||
ratio: '4:3',
|
||||
focusDepth: 0,
|
||||
type: CameraManager.Type.back,
|
||||
cameraId: null,
|
||||
autoFocus: CameraManager.AutoFocus.on,
|
||||
flashMode: CameraManager.FlashMode.off,
|
||||
exposure: -1,
|
||||
@ -516,6 +518,14 @@ export default class Camera extends React.Component<PropsType, StateType> {
|
||||
}
|
||||
}
|
||||
|
||||
async getCameraIdsAsync() {
|
||||
if (Platform.OS === 'android') {
|
||||
return await CameraManager.getCameraIds(this._cameraHandle);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
getAvailablePictureSizes = async (): string[] => {
|
||||
//$FlowFixMe
|
||||
return await CameraManager.getAvailablePictureSizes(this.props.ratio, this._cameraHandle);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user