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:
cristianoccazinsp 2019-09-24 10:47:23 -03:00 committed by Sibelius Seraphini
parent 200c7e136c
commit 612cb65f2a
8 changed files with 385 additions and 110 deletions

View File

@ -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() {

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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.

View File

@ -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);