2016-01-05 12:36:05 -08:00
/**
* Created by Fabrice Armisen (farmisen@gmail.com) on 1/4/16.
*/
package com.lwansbrough.RCTCamera ;
import android.hardware.Camera ;
2016-08-27 20:49:46 -05:00
import android.media.CamcorderProfile ;
2016-09-01 11:55:22 -07:00
import android.util.Log ;
2016-01-05 12:36:05 -08:00
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
public class RCTCamera {
2016-09-12 20:20:46 -07:00
private static RCTCamera ourInstance ;
2016-01-05 12:36:05 -08:00
private final HashMap < Integer , CameraInfoWrapper > _cameraInfos ;
private final HashMap < Integer , Integer > _cameraTypeToIndex ;
private final Map < Number , Camera > _cameras ;
2016-11-18 14:38:23 -08:00
private static final Resolution RESOLUTION_480P = new Resolution ( 853 , 480 ); // 480p shoots for a 16:9 HD aspect ratio, but can otherwise fall back/down to any other supported camera sizes, such as 800x480 or 720x480, if (any) present. See getSupportedPictureSizes/getSupportedVideoSizes below.
private static final Resolution RESOLUTION_720P = new Resolution ( 1280 , 720 );
private static final Resolution RESOLUTION_1080P = new Resolution ( 1920 , 1080 );
2016-09-15 00:57:11 +02:00
private boolean _barcodeScannerEnabled = false ;
2016-09-15 21:30:00 +02:00
private List < String > _barCodeTypes = null ;
2016-01-05 12:36:05 -08:00
private int _orientation = - 1 ;
private int _actualDeviceOrientation = 0 ;
2016-08-27 20:49:46 -05:00
private int _adjustedDeviceOrientation = 0 ;
2016-01-05 12:36:05 -08:00
public static RCTCamera getInstance () {
return ourInstance ;
}
2016-09-12 20:20:46 -07:00
public static void createInstance ( int deviceOrientation ) {
ourInstance = new RCTCamera ( deviceOrientation );
}
2016-01-05 12:36:05 -08:00
public Camera acquireCameraInstance ( int type ) {
if ( null == _cameras . get ( type ) && null != _cameraTypeToIndex . get ( type )) {
try {
Camera camera = Camera . open ( _cameraTypeToIndex . get ( type ));
_cameras . put ( type , camera );
adjustPreviewLayout ( type );
} catch ( Exception e ) {
2016-09-01 11:55:22 -07:00
Log . e ( "RCTCamera" , "acquireCameraInstance failed" , e );
2016-01-05 12:36:05 -08:00
}
}
return _cameras . get ( type );
}
public void releaseCameraInstance ( int type ) {
if ( null != _cameras . get ( type )) {
_cameras . get ( type ). release ();
_cameras . remove ( type );
}
}
public int getPreviewWidth ( int type ) {
CameraInfoWrapper cameraInfo = _cameraInfos . get ( type );
if ( null == cameraInfo ) {
return 0 ;
}
return cameraInfo . previewWidth ;
}
public int getPreviewHeight ( int type ) {
CameraInfoWrapper cameraInfo = _cameraInfos . get ( type );
if ( null == cameraInfo ) {
return 0 ;
}
return cameraInfo . previewHeight ;
}
2016-08-27 20:49:46 -05:00
public Camera . Size getBestSize ( List < Camera . Size > supportedSizes , int maxWidth , int maxHeight ) {
Camera . Size bestSize = null ;
for ( Camera . Size size : supportedSizes ) {
if ( size . width > maxWidth || size . height > maxHeight ) {
continue ;
}
2016-03-20 21:31:23 +02:00
2016-08-27 20:49:46 -05:00
if ( bestSize == null ) {
bestSize = size ;
continue ;
}
int resultArea = bestSize . width * bestSize . height ;
int newArea = size . width * size . height ;
if ( newArea > resultArea ) {
bestSize = size ;
2016-03-20 21:31:23 +02:00
}
}
2016-08-27 20:49:46 -05:00
return bestSize ;
2016-03-20 21:31:23 +02:00
}
2016-08-27 20:49:46 -05:00
private Camera . Size getSmallestSize ( List < Camera . Size > supportedSizes ) {
Camera . Size smallestSize = null ;
for ( Camera . Size size : supportedSizes ) {
if ( smallestSize == null ) {
smallestSize = size ;
continue ;
}
2016-03-20 21:31:23 +02:00
2016-08-27 20:49:46 -05:00
int resultArea = smallestSize . width * smallestSize . height ;
int newArea = size . width * size . height ;
if ( newArea < resultArea ) {
smallestSize = size ;
2016-03-20 21:31:23 +02:00
}
}
2016-08-27 20:49:46 -05:00
return smallestSize ;
2016-03-20 21:31:23 +02:00
}
2016-11-17 22:25:51 -08:00
protected List < Camera . Size > getSupportedVideoSizes ( Camera camera ) {
2016-03-20 21:31:23 +02:00
Camera . Parameters params = camera . getParameters ();
2016-08-27 20:49:46 -05:00
// defer to preview instead of params.getSupportedVideoSizes() http://bit.ly/1rxOsq0
// but prefer SupportedVideoSizes!
List < Camera . Size > sizes = params . getSupportedVideoSizes ();
if ( sizes != null ) {
return sizes ;
2016-03-20 21:31:23 +02:00
}
2016-08-27 20:49:46 -05:00
// Video sizes may be null, which indicates that all the supported
// preview sizes are supported for video recording.
return params . getSupportedPreviewSizes ();
2016-03-20 21:31:23 +02:00
}
2016-05-10 21:05:03 +03:00
public int getOrientation () {
return _orientation ;
}
2016-01-05 12:36:05 -08:00
public void setOrientation ( int orientation ) {
if ( _orientation == orientation ) {
return ;
}
_orientation = orientation ;
adjustPreviewLayout ( RCTCameraModule . RCT_CAMERA_TYPE_FRONT );
adjustPreviewLayout ( RCTCameraModule . RCT_CAMERA_TYPE_BACK );
}
2016-09-15 00:57:11 +02:00
public boolean isBarcodeScannerEnabled () {
return _barcodeScannerEnabled ;
}
public void setBarcodeScannerEnabled ( boolean barcodeScannerEnabled ) {
_barcodeScannerEnabled = barcodeScannerEnabled ;
}
2016-09-15 21:30:00 +02:00
public List < String > getBarCodeTypes () {
return _barCodeTypes ;
}
public void setBarCodeTypes ( List < String > barCodeTypes ) {
_barCodeTypes = barCodeTypes ;
}
2016-08-27 20:49:46 -05:00
public int getActualDeviceOrientation () {
return _actualDeviceOrientation ;
}
public void setAdjustedDeviceOrientation ( int orientation ) {
_adjustedDeviceOrientation = orientation ;
}
public int getAdjustedDeviceOrientation () {
return _adjustedDeviceOrientation ;
}
2016-01-05 12:36:05 -08:00
public void setActualDeviceOrientation ( int actualDeviceOrientation ) {
_actualDeviceOrientation = actualDeviceOrientation ;
adjustPreviewLayout ( RCTCameraModule . RCT_CAMERA_TYPE_FRONT );
adjustPreviewLayout ( RCTCameraModule . RCT_CAMERA_TYPE_BACK );
}
2016-11-17 22:25:51 -08:00
public void setCaptureMode ( final int cameraType , final int captureMode ) {
Camera camera = _cameras . get ( cameraType );
if ( camera == null ) {
return ;
}
// Set (video) recording hint based on camera type. For video recording, setting
// this hint can help reduce the time it takes to start recording.
Camera . Parameters parameters = camera . getParameters ();
parameters . setRecordingHint ( captureMode == RCTCameraModule . RCT_CAMERA_CAPTURE_MODE_VIDEO );
camera . setParameters ( parameters );
}
2016-03-20 21:31:23 +02:00
public void setCaptureQuality ( int cameraType , String captureQuality ) {
Camera camera = _cameras . get ( cameraType );
2016-08-27 20:49:46 -05:00
if ( camera == null ) {
2016-03-20 21:31:23 +02:00
return ;
}
Camera . Parameters parameters = camera . getParameters ();
Camera . Size pictureSize = null ;
2016-11-18 14:38:23 -08:00
List < Camera . Size > supportedSizes = parameters . getSupportedPictureSizes ();
2016-03-20 21:31:23 +02:00
switch ( captureQuality ) {
2016-08-27 20:49:46 -05:00
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_LOW :
2016-11-18 14:38:23 -08:00
pictureSize = getSmallestSize ( supportedSizes );
2016-03-20 21:31:23 +02:00
break ;
2016-08-27 20:49:46 -05:00
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_MEDIUM :
2016-11-18 14:38:23 -08:00
pictureSize = supportedSizes . get ( supportedSizes . size () / 2 );
2016-03-20 21:31:23 +02:00
break ;
2016-08-27 20:49:46 -05:00
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_HIGH :
2016-11-18 14:38:23 -08:00
pictureSize = getBestSize ( supportedSizes , Integer . MAX_VALUE , Integer . MAX_VALUE );
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_480P :
pictureSize = getBestSize ( supportedSizes , RESOLUTION_480P . width , RESOLUTION_480P . height );
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_720P :
pictureSize = getBestSize ( supportedSizes , RESOLUTION_720P . width , RESOLUTION_720P . height );
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_1080P :
pictureSize = getBestSize ( supportedSizes , RESOLUTION_1080P . width , RESOLUTION_1080P . height );
break ;
2016-03-20 21:31:23 +02:00
}
if ( pictureSize != null ) {
parameters . setPictureSize ( pictureSize . width , pictureSize . height );
camera . setParameters ( parameters );
}
}
2016-08-27 20:49:46 -05:00
public CamcorderProfile setCaptureVideoQuality ( int cameraType , String captureQuality ) {
Camera camera = _cameras . get ( cameraType );
if ( camera == null ) {
return null ;
}
Camera . Size videoSize = null ;
2016-11-18 14:38:23 -08:00
List < Camera . Size > supportedSizes = getSupportedVideoSizes ( camera );
2016-08-27 20:49:46 -05:00
CamcorderProfile cm = null ;
switch ( captureQuality ) {
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_LOW :
2016-11-18 14:38:23 -08:00
videoSize = getSmallestSize ( supportedSizes );
2016-08-27 20:49:46 -05:00
cm = CamcorderProfile . get ( _cameraTypeToIndex . get ( cameraType ), CamcorderProfile . QUALITY_480P );
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_MEDIUM :
2016-11-18 14:38:23 -08:00
videoSize = supportedSizes . get ( supportedSizes . size () / 2 );
2016-08-27 20:49:46 -05:00
cm = CamcorderProfile . get ( _cameraTypeToIndex . get ( cameraType ), CamcorderProfile . QUALITY_720P );
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_HIGH :
2016-11-18 14:38:23 -08:00
videoSize = getBestSize ( supportedSizes , Integer . MAX_VALUE , Integer . MAX_VALUE );
2016-08-27 20:49:46 -05:00
cm = CamcorderProfile . get ( _cameraTypeToIndex . get ( cameraType ), CamcorderProfile . QUALITY_HIGH );
2016-11-18 14:38:23 -08:00
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_480P :
videoSize = getBestSize ( supportedSizes , RESOLUTION_480P . width , RESOLUTION_480P . height );
cm = CamcorderProfile . get ( _cameraTypeToIndex . get ( cameraType ), CamcorderProfile . QUALITY_480P );
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_720P :
videoSize = getBestSize ( supportedSizes , RESOLUTION_720P . width , RESOLUTION_720P . height );
cm = CamcorderProfile . get ( _cameraTypeToIndex . get ( cameraType ), CamcorderProfile . QUALITY_720P );
break ;
case RCTCameraModule . RCT_CAMERA_CAPTURE_QUALITY_1080P :
videoSize = getBestSize ( supportedSizes , RESOLUTION_1080P . width , RESOLUTION_1080P . height );
cm = CamcorderProfile . get ( _cameraTypeToIndex . get ( cameraType ), CamcorderProfile . QUALITY_1080P );
break ;
2016-08-27 20:49:46 -05:00
}
if ( cm == null ){
return null ;
}
if ( videoSize != null ) {
cm . videoFrameHeight = videoSize . height ;
cm . videoFrameWidth = videoSize . width ;
}
return cm ;
}
2016-01-05 12:36:05 -08:00
public void setTorchMode ( int cameraType , int torchMode ) {
Camera camera = _cameras . get ( cameraType );
if ( null == camera ) {
return ;
}
Camera . Parameters parameters = camera . getParameters ();
String value = parameters . getFlashMode ();
switch ( torchMode ) {
case RCTCameraModule . RCT_CAMERA_TORCH_MODE_ON :
value = Camera . Parameters . FLASH_MODE_TORCH ;
break ;
case RCTCameraModule . RCT_CAMERA_TORCH_MODE_OFF :
value = Camera . Parameters . FLASH_MODE_OFF ;
break ;
}
List < String > flashModes = parameters . getSupportedFlashModes ();
if ( flashModes != null && flashModes . contains ( value )) {
parameters . setFlashMode ( value );
camera . setParameters ( parameters );
}
}
public void setFlashMode ( int cameraType , int flashMode ) {
Camera camera = _cameras . get ( cameraType );
if ( null == camera ) {
return ;
}
Camera . Parameters parameters = camera . getParameters ();
String value = parameters . getFlashMode ();
switch ( flashMode ) {
case RCTCameraModule . RCT_CAMERA_FLASH_MODE_AUTO :
value = Camera . Parameters . FLASH_MODE_AUTO ;
break ;
case RCTCameraModule . RCT_CAMERA_FLASH_MODE_ON :
value = Camera . Parameters . FLASH_MODE_ON ;
break ;
case RCTCameraModule . RCT_CAMERA_FLASH_MODE_OFF :
value = Camera . Parameters . FLASH_MODE_OFF ;
break ;
}
List < String > flashModes = parameters . getSupportedFlashModes ();
if ( flashModes != null && flashModes . contains ( value )) {
parameters . setFlashMode ( value );
camera . setParameters ( parameters );
}
}
2016-08-27 20:49:46 -05:00
public void adjustCameraRotationToDeviceOrientation ( int type , int deviceOrientation ) {
2016-03-23 14:16:39 +02:00
Camera camera = _cameras . get ( type );
if ( null == camera ) {
return ;
}
CameraInfoWrapper cameraInfo = _cameraInfos . get ( type );
int rotation ;
int orientation = cameraInfo . info . orientation ;
if ( cameraInfo . info . facing == Camera . CameraInfo . CAMERA_FACING_FRONT ) {
rotation = ( orientation + deviceOrientation * 90 ) % 360 ;
} else {
rotation = ( orientation - deviceOrientation * 90 + 360 ) % 360 ;
}
cameraInfo . rotation = rotation ;
Camera . Parameters parameters = camera . getParameters ();
parameters . setRotation ( cameraInfo . rotation );
try {
camera . setParameters ( parameters );
} catch ( Exception e ) {
e . printStackTrace ();
}
}
2016-08-27 20:49:46 -05:00
public void adjustPreviewLayout ( int type ) {
2016-01-05 12:36:05 -08:00
Camera camera = _cameras . get ( type );
if ( null == camera ) {
return ;
}
CameraInfoWrapper cameraInfo = _cameraInfos . get ( type );
2016-02-18 18:10:56 +02:00
int displayRotation ;
int rotation ;
int orientation = cameraInfo . info . orientation ;
2016-01-05 12:36:05 -08:00
if ( cameraInfo . info . facing == Camera . CameraInfo . CAMERA_FACING_FRONT ) {
2016-02-18 18:10:56 +02:00
rotation = ( orientation + _actualDeviceOrientation * 90 ) % 360 ;
displayRotation = ( 720 - orientation - _actualDeviceOrientation * 90 ) % 360 ;
2016-01-05 12:36:05 -08:00
} else {
2016-02-18 18:10:56 +02:00
rotation = ( orientation - _actualDeviceOrientation * 90 + 360 ) % 360 ;
displayRotation = rotation ;
2016-01-05 12:36:05 -08:00
}
cameraInfo . rotation = rotation ;
// TODO: take in account the _orientation prop
2016-09-03 12:35:09 -07:00
setAdjustedDeviceOrientation ( rotation );
2016-02-18 18:10:56 +02:00
camera . setDisplayOrientation ( displayRotation );
2016-01-05 12:36:05 -08:00
Camera . Parameters parameters = camera . getParameters ();
parameters . setRotation ( cameraInfo . rotation );
// set preview size
2016-03-20 21:31:23 +02:00
// defaults to highest resolution available
2016-08-27 20:49:46 -05:00
Camera . Size optimalPreviewSize = getBestSize ( parameters . getSupportedPreviewSizes (), Integer . MAX_VALUE , Integer . MAX_VALUE );
2016-03-20 21:31:23 +02:00
int width = optimalPreviewSize . width ;
int height = optimalPreviewSize . height ;
2016-01-05 12:36:05 -08:00
parameters . setPreviewSize ( width , height );
try {
camera . setParameters ( parameters );
} catch ( Exception e ) {
e . printStackTrace ();
}
if ( cameraInfo . rotation == 0 || cameraInfo . rotation == 180 ) {
cameraInfo . previewWidth = width ;
cameraInfo . previewHeight = height ;
} else {
cameraInfo . previewWidth = height ;
cameraInfo . previewHeight = width ;
}
}
2016-09-12 20:20:46 -07:00
private RCTCamera ( int deviceOrientation ) {
2016-01-05 12:36:05 -08:00
_cameras = new HashMap <> ();
_cameraInfos = new HashMap <> ();
_cameraTypeToIndex = new HashMap <> ();
2016-09-12 20:20:46 -07:00
_actualDeviceOrientation = deviceOrientation ;
2016-01-05 12:36:05 -08:00
// map camera types to camera indexes and collect cameras properties
for ( int i = 0 ; i < Camera . getNumberOfCameras (); i ++ ) {
Camera . CameraInfo info = new Camera . CameraInfo ();
Camera . getCameraInfo ( i , info );
if ( info . facing == Camera . CameraInfo . CAMERA_FACING_FRONT && _cameraInfos . get ( RCTCameraModule . RCT_CAMERA_TYPE_FRONT ) == null ) {
_cameraInfos . put ( RCTCameraModule . RCT_CAMERA_TYPE_FRONT , new CameraInfoWrapper ( info ));
_cameraTypeToIndex . put ( RCTCameraModule . RCT_CAMERA_TYPE_FRONT , i );
acquireCameraInstance ( RCTCameraModule . RCT_CAMERA_TYPE_FRONT );
releaseCameraInstance ( RCTCameraModule . RCT_CAMERA_TYPE_FRONT );
} else if ( info . facing == Camera . CameraInfo . CAMERA_FACING_BACK && _cameraInfos . get ( RCTCameraModule . RCT_CAMERA_TYPE_BACK ) == null ) {
_cameraInfos . put ( RCTCameraModule . RCT_CAMERA_TYPE_BACK , new CameraInfoWrapper ( info ));
_cameraTypeToIndex . put ( RCTCameraModule . RCT_CAMERA_TYPE_BACK , i );
acquireCameraInstance ( RCTCameraModule . RCT_CAMERA_TYPE_BACK );
releaseCameraInstance ( RCTCameraModule . RCT_CAMERA_TYPE_BACK );
}
}
}
private class CameraInfoWrapper {
public final Camera . CameraInfo info ;
public int rotation = 0 ;
public int previewWidth = - 1 ;
public int previewHeight = - 1 ;
public CameraInfoWrapper ( Camera . CameraInfo info ) {
this . info = info ;
}
}
2016-11-18 14:38:23 -08:00
private static class Resolution {
public int width ;
public int height ;
public Resolution ( final int width , final int height ) {
this . width = width ;
this . height = height ;
}
}
2016-01-05 12:36:05 -08:00
}