@ -19,6 +19,9 @@ import java.util.ArrayList;
import java.util.Collections ;
import java.util.Collections ;
import java.util.List ;
import java.util.List ;
import static android.hardware.Camera.CAMERA_ERROR_SERVER_DIED ;
import static android.hardware.Camera.CAMERA_ERROR_UNKNOWN ;
@SuppressWarnings ( "deprecation" )
@SuppressWarnings ( "deprecation" )
class Camera1 extends CameraController {
class Camera1 extends CameraController {
@ -37,14 +40,24 @@ class Camera1 extends CameraController {
private Runnable mPostFocusResetRunnable = new Runnable ( ) {
private Runnable mPostFocusResetRunnable = new Runnable ( ) {
@Override
@Override
public void run ( ) {
public void run ( ) {
if ( ! isCameraAvailable ( ) ) return ;
try {
mCamera . cancelAutoFocus ( ) ;
if ( ! isCameraAvailable ( ) ) return ;
synchronized ( mLock ) {
mCamera . cancelAutoFocus ( ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
params . setFocusAreas ( null ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
params . setMeteringAreas ( null ) ;
params . setFocusAreas ( null ) ;
applyDefaultFocus ( params ) ; // Revert to internal focus.
params . setMeteringAreas ( null ) ;
mCamera . setParameters ( params ) ;
applyDefaultFocus ( params ) ; // Revert to internal focus.
mCamera . setParameters ( params ) ;
}
}
catch ( Exception e ) {
// at least setParameters may fail.
// problem may be device-specific to the Samsung Galaxy J5
// TODO why does it fail occasionally and is it possible to prevent such errors?
CameraException cameraException = new CameraConfigurationFailedException ( "Failed to " +
"reset auto focus." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
}
}
}
}
} ;
} ;
@ -75,8 +88,9 @@ class Camera1 extends CameraController {
try {
try {
setup ( ) ;
setup ( ) ;
} catch ( Exception e ) {
} catch ( Exception e ) {
LOG . w ( "onSurfaceAvailable:" , "Exception while binding camera to preview." , e ) ;
CameraException cameraException = new CameraUnavailableException (
throw new RuntimeException ( e ) ;
"onSurfaceAvailable: Exception while binding camera to preview." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
}
}
}
}
} ) ;
} ) ;
@ -164,6 +178,38 @@ class Camera1 extends CameraController {
if ( collectCameraId ( ) ) {
if ( collectCameraId ( ) ) {
mCamera = Camera . open ( mCameraId ) ;
mCamera = Camera . open ( mCameraId ) ;
/ * *
* attach Android native error listener for the Camera1 API
* TODO it ' s not yet sure how the caught errors interact with the exceptions caught
* outside of the following handler . Furthermore , for most errors it ' s not known whether
* they are crucial or not . Therefore , such errors are handled as low - priority
* CameraConfigurationFailedExceptions for now .
* /
mCamera . setErrorCallback ( new Camera . ErrorCallback ( ) {
@Override
public void onError ( int errorCode , Camera camera ) {
// extend error information by known error codes
CameraException cameraException ;
if ( errorCode = = CAMERA_ERROR_SERVER_DIED ) {
cameraException = new CameraUnavailableException (
"Media server died. In this case, the application must release the" +
" Camera object and instantiate a new one." ) ;
}
else if ( errorCode = = CAMERA_ERROR_UNKNOWN ) {
cameraException = new CameraConfigurationFailedException (
"Unspecified camera error." ) ;
}
else {
cameraException = new CameraConfigurationFailedException (
"Received camera error code: " + errorCode ) ;
}
// redirect error
mCameraCallbacks . onError ( cameraException ) ;
}
} ) ;
// Set parameters that might have been set before the camera was opened.
// Set parameters that might have been set before the camera was opened.
synchronized ( mLock ) {
synchronized ( mLock ) {
LOG . i ( "onStart:" , "Applying default parameters." ) ;
LOG . i ( "onStart:" , "Applying default parameters." ) ;
@ -250,14 +296,21 @@ class Camera1 extends CameraController {
@Override
@Override
void setLocation ( Location location ) {
void setLocation ( Location location ) {
Location oldLocation = mLocation ;
try {
mLocation = location ;
Location oldLocation = mLocation ;
if ( isCameraAvailable ( ) ) {
mLocation = location ;
synchronized ( mLock ) {
if ( isCameraAvailable ( ) ) {
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
if ( mergeLocation ( params , oldLocation ) ) mCamera . setParameters ( params ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
if ( mergeLocation ( params , oldLocation ) ) mCamera . setParameters ( params ) ;
}
}
}
}
}
catch ( Exception e ) {
CameraException cameraException =
new CameraConfigurationFailedException ( "Failed to set the location." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
}
}
}
private boolean mergeLocation ( Camera . Parameters params , Location oldLocation ) {
private boolean mergeLocation ( Camera . Parameters params , Location oldLocation ) {
@ -288,14 +341,22 @@ class Camera1 extends CameraController {
@Override
@Override
void setWhiteBalance ( WhiteBalance whiteBalance ) {
void setWhiteBalance ( WhiteBalance whiteBalance ) {
WhiteBalance old = mWhiteBalance ;
try {
mWhiteBalance = whiteBalance ;
WhiteBalance old = mWhiteBalance ;
if ( isCameraAvailable ( ) ) {
mWhiteBalance = whiteBalance ;
synchronized ( mLock ) {
if ( isCameraAvailable ( ) ) {
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
if ( mergeWhiteBalance ( params , old ) ) mCamera . setParameters ( params ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
if ( mergeWhiteBalance ( params , old ) ) mCamera . setParameters ( params ) ;
}
}
}
}
}
catch ( Exception e ) {
// TODO handle, !mergeWhiteBalance, too?
CameraException cameraException =
new CameraConfigurationFailedException ( "Failed to set the white balance." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
}
}
}
private boolean mergeWhiteBalance ( Camera . Parameters params , WhiteBalance oldWhiteBalance ) {
private boolean mergeWhiteBalance ( Camera . Parameters params , WhiteBalance oldWhiteBalance ) {
@ -309,14 +370,22 @@ class Camera1 extends CameraController {
@Override
@Override
void setHdr ( Hdr hdr ) {
void setHdr ( Hdr hdr ) {
Hdr old = mHdr ;
try {
mHdr = hdr ;
Hdr old = mHdr ;
if ( isCameraAvailable ( ) ) {
mHdr = hdr ;
synchronized ( mLock ) {
if ( isCameraAvailable ( ) ) {
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
if ( mergeHdr ( params , old ) ) mCamera . setParameters ( params ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
if ( mergeHdr ( params , old ) ) mCamera . setParameters ( params ) ;
}
}
}
}
}
catch ( Exception e ) {
// TODO handle, !mergeHdr, too?
CameraException cameraException =
new CameraConfigurationFailedException ( "Failed to set hdr." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
}
}
}
private boolean mergeHdr ( Camera . Parameters params , Hdr oldHdr ) {
private boolean mergeHdr ( Camera . Parameters params , Hdr oldHdr ) {
@ -341,14 +410,22 @@ class Camera1 extends CameraController {
@Override
@Override
void setFlash ( Flash flash ) {
void setFlash ( Flash flash ) {
Flash old = mFlash ;
try {
mFlash = flash ;
Flash old = mFlash ;
if ( isCameraAvailable ( ) ) {
mFlash = flash ;
synchronized ( mLock ) {
if ( isCameraAvailable ( ) ) {
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
if ( mergeFlash ( params , old ) ) mCamera . setParameters ( params ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
if ( mergeFlash ( params , old ) ) mCamera . setParameters ( params ) ;
}
}
}
}
}
catch ( Exception e ) {
// TODO handle, !mergeFlash, too?
CameraException cameraException =
new CameraConfigurationFailedException ( "Failed to set flash." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
}
}
}
@ -391,29 +468,37 @@ class Camera1 extends CameraController {
@Override
@Override
void setVideoQuality ( VideoQuality videoQuality ) {
void setVideoQuality ( VideoQuality videoQuality ) {
if ( mIsCapturingVideo ) {
// TODO: actually any call to getParameters() could fail while recording a video.
try {
// See. https://stackoverflow.com/questions/14941625/correct-handling-of-exception-getparameters-failed-empty-parameters
if ( mIsCapturingVideo ) {
throw new IllegalStateException ( "Can't change video quality while recording a video." ) ;
// TODO: actually any call to getParameters() could fail while recording a video.
}
// See. https://stackoverflow.com/questions/14941625/correct-handling-of-exception-getparameters-failed-empty-parameters
throw new IllegalStateException ( "Can't change video quality while recording a video." ) ;
mVideoQuality = videoQuality ;
}
if ( isCameraAvailable ( ) & & mSessionType = = SessionType . VIDEO ) {
// Change capture size to a size that fits the video aspect ratio.
mVideoQuality = videoQuality ;
Size oldSize = mCaptureSize ;
if ( isCameraAvailable ( ) & & mSessionType = = SessionType . VIDEO ) {
mCaptureSize = computeCaptureSize ( ) ;
// Change capture size to a size that fits the video aspect ratio.
if ( ! mCaptureSize . equals ( oldSize ) ) {
Size oldSize = mCaptureSize ;
// New video quality triggers a new aspect ratio.
mCaptureSize = computeCaptureSize ( ) ;
// Go on and see if preview size should change also.
if ( ! mCaptureSize . equals ( oldSize ) ) {
synchronized ( mLock ) {
// New video quality triggers a new aspect ratio.
Camera . Parameters params = mCamera . getParameters ( ) ;
// Go on and see if preview size should change also.
params . setPictureSize ( mCaptureSize . getWidth ( ) , mCaptureSize . getHeight ( ) ) ;
synchronized ( mLock ) {
mCamera . setParameters ( params ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
params . setPictureSize ( mCaptureSize . getWidth ( ) , mCaptureSize . getHeight ( ) ) ;
mCamera . setParameters ( params ) ;
}
onSurfaceChanged ( ) ;
}
}
onSurfaceChanged ( ) ;
LOG . i ( "setVideoQuality:" , "captureSize:" , mCaptureSize ) ;
LOG . i ( "setVideoQuality:" , "previewSize:" , mPreviewSize ) ;
}
}
LOG . i ( "setVideoQuality:" , "captureSize:" , mCaptureSize ) ;
}
LOG . i ( "setVideoQuality:" , "previewSize:" , mPreviewSize ) ;
catch ( Exception e ) {
CameraException cameraException =
new CameraConfigurationFailedException ( "Failed to set video quality." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
}
}
}
}
@ -425,36 +510,43 @@ class Camera1 extends CameraController {
if ( ! mOptions . isVideoSnapshotSupported ( ) ) return false ;
if ( ! mOptions . isVideoSnapshotSupported ( ) ) return false ;
}
}
// Set boolean to wait for image callback
try {
mIsCapturingImage = true ;
// Set boolean to wait for image callback
final int exifRotation = computeExifRotation ( ) ;
mIsCapturingImage = true ;
final boolean exifFlip = computeExifFlip ( ) ;
final int exifRotation = computeExifRotation ( ) ;
final int sensorToDisplay = computeSensorToDisplayOffset ( ) ;
final boolean exifFlip = computeExifFlip ( ) ;
synchronized ( mLock ) {
final int sensorToDisplay = computeSensorToDisplayOffset ( ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
params . setRotation ( exifRotation ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
mCamera . setParameters ( params ) ;
params . setRotation ( exifRotation ) ;
mCamera . setParameters ( params ) ;
}
// Is the final picture (decoded respecting EXIF) consistent with CameraView orientation?
// We must consider exifOrientation to bring back the picture in the sensor world.
// Then use sensorToDisplay to move to the display world, where CameraView lives.
final boolean consistentWithView = ( exifRotation + sensorToDisplay + 180 ) % 180 = = 0 ;
mCamera . takePicture ( null , null , null ,
new Camera . PictureCallback ( ) {
@Override
public void onPictureTaken ( byte [ ] data , final Camera camera ) {
mIsCapturingImage = false ;
mHandler . post ( new Runnable ( ) {
@Override
public void run ( ) {
// This is needed, read somewhere in the docs.
camera . startPreview ( ) ;
}
} ) ;
mCameraCallbacks . processImage ( data , consistentWithView , exifFlip ) ;
}
} ) ;
return true ;
}
catch ( Exception e ) {
CameraException cameraException = new CapturingPictureFailedException ( "Capturing a picture failed." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
return false ;
}
}
// Is the final picture (decoded respecting EXIF) consistent with CameraView orientation?
// We must consider exifOrientation to bring back the picture in the sensor world.
// Then use sensorToDisplay to move to the display world, where CameraView lives.
final boolean consistentWithView = ( exifRotation + sensorToDisplay + 180 ) % 180 = = 0 ;
mCamera . takePicture ( null , null , null ,
new Camera . PictureCallback ( ) {
@Override
public void onPictureTaken ( byte [ ] data , final Camera camera ) {
mIsCapturingImage = false ;
mHandler . post ( new Runnable ( ) {
@Override
public void run ( ) {
// This is needed, read somewhere in the docs.
camera . startPreview ( ) ;
}
} ) ;
mCameraCallbacks . processImage ( data , consistentWithView , exifFlip ) ;
}
} ) ;
return true ;
}
}
@ -468,37 +560,45 @@ class Camera1 extends CameraController {
capturePicture ( ) ;
capturePicture ( ) ;
return false ;
return false ;
}
}
mIsCapturingImage = true ;
mCamera . setOneShotPreviewCallback ( new Camera . PreviewCallback ( ) {
@Override
public void onPreviewFrame ( final byte [ ] data , Camera camera ) {
// Got to rotate the preview frame, since byte[] data here does not include
// EXIF tags automatically set by camera. So either we add EXIF, or we rotate.
// Adding EXIF to a byte array, unfortunately, is hard.
Camera . Parameters params = mCamera . getParameters ( ) ;
final int sensorToDevice = computeExifRotation ( ) ;
final int sensorToDisplay = computeSensorToDisplayOffset ( ) ;
final boolean exifFlip = computeExifFlip ( ) ;
final boolean flip = sensorToDevice % 180 ! = 0 ;
final int preWidth = mPreviewSize . getWidth ( ) ;
final int preHeight = mPreviewSize . getHeight ( ) ;
final int postWidth = flip ? preHeight : preWidth ;
final int postHeight = flip ? preWidth : preHeight ;
final int format = params . getPreviewFormat ( ) ;
WorkerHandler . run ( new Runnable ( ) {
@Override
public void run ( ) {
final boolean consistentWithView = ( sensorToDevice + sensorToDisplay + 180 ) % 180 = = 0 ;
try {
byte [ ] rotatedData = RotationHelper . rotate ( data , preWidth , preHeight , sensorToDevice ) ;
mIsCapturingImage = true ;
YuvImage yuv = new YuvImage ( rotatedData , format , postWidth , postHeight , null ) ;
mCamera . setOneShotPreviewCallback ( new Camera . PreviewCallback ( ) {
mCameraCallbacks . processSnapshot ( yuv , consistentWithView , exifFlip ) ;
@Override
mIsCapturingImage = false ;
public void onPreviewFrame ( final byte [ ] data , Camera camera ) {
}
// Got to rotate the preview frame, since byte[] data here does not include
} ) ;
// EXIF tags automatically set by camera. So either we add EXIF, or we rotate.
}
// Adding EXIF to a byte array, unfortunately, is hard.
} ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
return true ;
final int sensorToDevice = computeExifRotation ( ) ;
final int sensorToDisplay = computeSensorToDisplayOffset ( ) ;
final boolean exifFlip = computeExifFlip ( ) ;
final boolean flip = sensorToDevice % 180 ! = 0 ;
final int preWidth = mPreviewSize . getWidth ( ) ;
final int preHeight = mPreviewSize . getHeight ( ) ;
final int postWidth = flip ? preHeight : preWidth ;
final int postHeight = flip ? preWidth : preHeight ;
final int format = params . getPreviewFormat ( ) ;
WorkerHandler . run ( new Runnable ( ) {
@Override
public void run ( ) {
final boolean consistentWithView = ( sensorToDevice + sensorToDisplay + 180 ) % 180 = = 0 ;
byte [ ] rotatedData = RotationHelper . rotate ( data , preWidth , preHeight , sensorToDevice ) ;
YuvImage yuv = new YuvImage ( rotatedData , format , postWidth , postHeight , null ) ;
mCameraCallbacks . processSnapshot ( yuv , consistentWithView , exifFlip ) ;
mIsCapturingImage = false ;
}
} ) ;
}
} ) ;
return true ;
}
catch ( Exception e ) {
CameraException cameraException = new CapturingSnapshotFailedException ( "Capturing a snapshot failed." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
return false ;
}
}
}
@Override
@Override
@ -619,14 +719,20 @@ class Camera1 extends CameraController {
mMediaRecorder . start ( ) ;
mMediaRecorder . start ( ) ;
return true ;
return true ;
} catch ( Exception e ) {
} catch ( Exception e ) {
LOG . e ( "Error while starting MediaRecorder. Swallowing." , e ) ;
CameraException cameraException =
new CapturingVideoFailedException ( "Error while starting MediaRecorder. " +
"Swallowing." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
mVideoFile = null ;
mVideoFile = null ;
mCamera . lock ( ) ;
mCamera . lock ( ) ;
endVideo ( ) ;
endVideo ( ) ;
return false ;
return false ;
}
}
} else {
} else {
throw new IllegalStateException ( "Can't record video while session type is picture" ) ;
CameraException cameraException =
new CapturingVideoFailedException ( "Can't record video while session type is picture" ) ;
mCameraCallbacks . onError ( cameraException ) ;
return false ;
}
}
}
}
@ -736,32 +842,50 @@ class Camera1 extends CameraController {
@Override
@Override
boolean setZoom ( float zoom ) {
boolean setZoom ( float zoom ) {
if ( ! isCameraAvailable ( ) ) return false ;
try {
if ( ! mOptions . isZoomSupported ( ) ) return false ;
if ( ! isCameraAvailable ( ) ) return false ;
synchronized ( mLock ) {
if ( ! mOptions . isZoomSupported ( ) ) return false ;
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
float max = params . getMaxZoom ( ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
params . setZoom ( ( int ) ( zoom * max ) ) ;
float max = params . getMaxZoom ( ) ;
mCamera . setParameters ( params ) ;
params . setZoom ( ( int ) ( zoom * max ) ) ;
mCamera . setParameters ( params ) ;
}
return true ;
}
}
return true ;
catch ( Exception e ) {
CameraException cameraException =
new CameraConfigurationFailedException ( "Failed to set zoom." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
return false ;
}
}
}
@Override
@Override
boolean setExposureCorrection ( float EVvalue ) {
boolean setExposureCorrection ( float EVvalue ) {
if ( ! isCameraAvailable ( ) ) return false ;
try {
if ( ! mOptions . isExposureCorrectionSupported ( ) ) return false ;
if ( ! isCameraAvailable ( ) ) return false ;
float max = mOptions . getExposureCorrectionMaxValue ( ) ;
if ( ! mOptions . isExposureCorrectionSupported ( ) ) return false ;
float min = mOptions . getExposureCorrectionMinValue ( ) ;
float max = mOptions . getExposureCorrectionMaxValue ( ) ;
EVvalue = EVvalue < min ? min : EVvalue > max ? max : EVvalue ; // cap
float min = mOptions . getExposureCorrectionMinValue ( ) ;
synchronized ( mLock ) {
EVvalue = EVvalue < min ? min : EVvalue > max ? max : EVvalue ; // cap
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
int indexValue = ( int ) ( EVvalue / params . getExposureCompensationStep ( ) ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
params . setExposureCompensation ( indexValue ) ;
int indexValue = ( int ) ( EVvalue / params . getExposureCompensationStep ( ) ) ;
mCamera . setParameters ( params ) ;
params . setExposureCompensation ( indexValue ) ;
mCamera . setParameters ( params ) ;
}
return true ;
}
}
return true ;
catch ( Exception e ) {
CameraException cameraException =
new CameraConfigurationFailedException ( "Failed to set exposure correction." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
return false ;
}
}
}
// -----------------
// -----------------
@ -772,31 +896,42 @@ class Camera1 extends CameraController {
boolean startAutoFocus ( @Nullable final Gesture gesture , PointF point ) {
boolean startAutoFocus ( @Nullable final Gesture gesture , PointF point ) {
if ( ! isCameraAvailable ( ) ) return false ;
if ( ! isCameraAvailable ( ) ) return false ;
if ( ! mOptions . isAutoFocusSupported ( ) ) return false ;
if ( ! mOptions . isAutoFocusSupported ( ) ) return false ;
final PointF p = new PointF ( point . x , point . y ) ; // copy.
List < Camera . Area > meteringAreas2 = computeMeteringAreas ( p . x , p . y ) ;
try {
List < Camera . Area > meteringAreas1 = meteringAreas2 . subList ( 0 , 1 ) ;
final PointF p = new PointF ( point . x , point . y ) ; // copy.
synchronized ( mLock ) {
List < Camera . Area > meteringAreas2 = computeMeteringAreas ( p . x , p . y ) ;
// At this point we are sure that camera supports auto focus... right? Look at CameraView.onTouchEvent().
List < Camera . Area > meteringAreas1 = meteringAreas2 . subList ( 0 , 1 ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
synchronized ( mLock ) {
int maxAF = params . getMaxNumFocusAreas ( ) ;
// At this point we are sure that camera supports auto focus... right? Look at CameraView.onTouchEvent().
int maxAE = params . getMaxNumMeteringAreas ( ) ;
Camera . Parameters params = mCamera . getParameters ( ) ;
if ( maxAF > 0 ) params . setFocusAreas ( maxAF > 1 ? meteringAreas2 : meteringAreas1 ) ;
int maxAF = params . getMaxNumFocusAreas ( ) ;
if ( maxAE > 0 ) params . setMeteringAreas ( maxAE > 1 ? meteringAreas2 : meteringAreas1 ) ;
int maxAE = params . getMaxNumMeteringAreas ( ) ;
params . setFocusMode ( Camera . Parameters . FOCUS_MODE_AUTO ) ;
if ( maxAF > 0 ) params . setFocusAreas ( maxAF > 1 ? meteringAreas2 : meteringAreas1 ) ;
mCamera . setParameters ( params ) ;
if ( maxAE > 0 ) params . setMeteringAreas ( maxAE > 1 ? meteringAreas2 : meteringAreas1 ) ;
mCameraCallbacks . dispatchOnFocusStart ( gesture , p ) ;
params . setFocusMode ( Camera . Parameters . FOCUS_MODE_AUTO ) ;
// TODO this is not guaranteed to be called... Fix.
mCamera . setParameters ( params ) ;
mCamera . autoFocus ( new Camera . AutoFocusCallback ( ) {
mCameraCallbacks . dispatchOnFocusStart ( gesture , p ) ;
@Override
// TODO this is not guaranteed to be called... Fix.
public void onAutoFocus ( boolean success , Camera camera ) {
mCamera . autoFocus ( new Camera . AutoFocusCallback ( ) {
// TODO lock auto exposure and white balance for a while
@Override
mCameraCallbacks . dispatchOnFocusEnd ( gesture , success , p ) ;
public void onAutoFocus ( boolean success , Camera camera ) {
mHandler . get ( ) . removeCallbacks ( mPostFocusResetRunnable ) ;
// TODO lock auto exposure and white balance for a while
mHandler . get ( ) . postDelayed ( mPostFocusResetRunnable , mPostFocusResetDelay ) ;
mCameraCallbacks . dispatchOnFocusEnd ( gesture , success , p ) ;
}
mHandler . get ( ) . removeCallbacks ( mPostFocusResetRunnable ) ;
} ) ;
mHandler . get ( ) . postDelayed ( mPostFocusResetRunnable , mPostFocusResetDelay ) ;
}
} ) ;
}
return true ;
}
catch ( Exception e ) {
// at least getParameters and setParameters may fail.
// TODO why do they fail and is it possible to prevent such errors?
CameraException cameraException = new CameraConfigurationFailedException ( "Failed to " +
"start auto focus." , e ) ;
mCameraCallbacks . onError ( cameraException ) ;
return false ;
}
}
return true ;
}
}