Java Camera2 Api仅在android 28 pie设备中显示摄像头上的白色屏幕
我使用的是camera2 api,它在Pie之前的android版本上运行良好,但在android Pie设备上打开摄像头时,它会显示白色屏幕。我已经检查了模拟器,10台设备。 请帮帮我 应用程序build.gradleJava Camera2 Api仅在android 28 pie设备中显示摄像头上的白色屏幕,java,android,android-camera2,android-9.0-pie,Java,Android,Android Camera2,Android 9.0 Pie,我使用的是camera2 api,它在Pie之前的android版本上运行良好,但在android Pie设备上打开摄像头时,它会显示白色屏幕。我已经检查了模拟器,10台设备。 请帮帮我 应用程序build.gradle compileSdkVersion 29 defaultConfig { applicationId "xxx.xxx.xxx.xxx" minSdkVersion 23 targetSdkVersion 29 } 我还
compileSdkVersion 29
defaultConfig {
applicationId "xxx.xxx.xxx.xxx"
minSdkVersion 23
targetSdkVersion 29
}
我还声明了权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-feature android:name="android.hardware.camera.autofocus" />
我也注意到有时它只在第一次工作,然后第二次显示白色屏幕。
下面是捕获活动代码
public class CCaptureActivity extends AppCompatActivity
{
/**
* Activity creation handler.
* @param argSavedInstanceState Instance saved during previous session (unused).
*/
@Override
protected void onCreate ( final Bundle argSavedInstanceState )
{
super.onCreate ( argSavedInstanceState );
// Fetch the UI elements which will be updated programatically during activity runtime.
setContentView ( R.layout.activity_capture );
m_objDocumentAreaView = (CDocumentAreaView) findViewById ( R.id.corners_view );
m_objCameraView = (CCameraView) findViewById ( R.id.camera_view );
// Select the camera to use and initialize it as well as its preview and the needed handlers.
m_objPreviewImageListener = new CCaptureAnalysisRunner ();
setupCameraViewListener ();
setupCameraStatusCallback ();
m_objPreviewThread = new HandlerThread ( "PreviewUpdate" );
m_objCameraManager = (CameraManager) getSystemService ( Context.CAMERA_SERVICE );
getCamera ();
m_objHardwareStatus.onCreate ( this );
}
@Override
protected void onResume ()
{
super.onResume ();
m_objHardwareStatus.onResume ();
m_objIdrsCapture.onResume ( this );
openCamera ();
}
@Override
protected void onPause ()
{
m_objIdrsCapture.onPause ();
m_objHardwareStatus.onPause ();
closeCamera ();
super.onPause ();
}
private class CCaptureAnalysisRunner implements ImageReader.OnImageAvailableListener
{
public void onImageAvailable ( final ImageReader argImageReader )
{
final Image objCapturedImage = argImageReader.acquireLatestImage ();
// The image may be null sometimes, so skip processing in such case
if ( null != objCapturedImage )
{
final boolean bDocumentExposureOk = m_objHardwareStatus.isExposureOk ();
final boolean bCameraFocusSet = ( bDocumentExposureOk && m_objHardwareStatus.isFocusSet ());
final boolean bDeviceStable = ( bCameraFocusSet && m_objHardwareStatus.isDeviceStable ());
final CIdrsCapture.CWorker objWorker = (( bDeviceStable || m_bForceCapture ) ? m_objIdrsCapture.tryLock () : null );
if ( objWorker != null )
{
Log.i ( "CCaptureActivity", "An image is available and will be processed" );
objWorker.setCurrentCapture ( objCapturedImage );
objCapturedImage.close ();
AsyncTask.execute ( new Runnable ()
{
@Override
public void run ()
{
onImageAnalysisCompleted ( objWorker, objWorker.detectDocumentCorners ());
}
});
}
else
{
objCapturedImage.close ();
}
// In any case, the indicators must be updated
runOnUiThread ( new Runnable ()
{
@Override
public void run ()
{
if ( m_objDocumentAreaView.reduceIntensity ())
{
m_objCornersFlag.setChecked ( false );
m_objAreaFlag.setChecked ( false );
}
m_objExposureFlag.setChecked ( bDocumentExposureOk );
m_objFocusFlag.setChecked ( bCameraFocusSet );
m_objStabilityFlag.setChecked ( bDeviceStable );
m_objDocumentAreaView.invalidate ();
m_objExposureFlag.invalidate ();
m_objFocusFlag.invalidate ();
m_objStabilityFlag.invalidate ();
}
});
}
}
private void onImageAnalysisCompleted (final CIdrsCapture.CWorker argWorker, final CIdrsCapture.DocumentCorners argDocumentCorners)
{
if ( ! m_objIdrsCapture.isCaptureSelected ())
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
m_objCornersFlag.setChecked(argDocumentCorners.bCornersFound);
m_objAreaFlag.setChecked(argDocumentCorners.bTargetAreaOk);
if (argDocumentCorners.bCornersFound)
{
m_objDocumentAreaView.setDetectedCorners(argDocumentCorners.xiCorners, argDocumentCorners.bTargetAreaOk);
}
m_objDocumentAreaView.invalidate();
m_objCornersFlag.invalidate();
m_objAreaFlag.invalidate();
}
});
try
{
if (( argDocumentCorners.bCornersFound && argDocumentCorners.bTargetAreaOk ) || m_bForceCapture )
{
final int iCaptureQuality = m_bForceCapture ? 100 : argWorker.evaluateQuality ();
boolean bCurrentCaptureSelected = false;
boolean bCurrentCaptureForced = false;
synchronized ( m_objCaptureSelectionLock )
{
if (iCaptureQuality >= CAPTURE_QUALITY_THRESHOLD && ! m_objIdrsCapture.isCaptureSelected ())
{
argWorker.selectCapture();
bCurrentCaptureSelected = true;
if ( m_bForceCapture )
{
bCurrentCaptureForced = true;
m_bForceCapture = false;
}
}
}
// Update the controls only if no capture are currently selected or if this capture is the one selected
final boolean bCurrentCaptureSelectedFinal = bCurrentCaptureSelected;
final boolean bCurrentCaptureForcedFinal = bCurrentCaptureForced;
if ( bCurrentCaptureSelected || ! m_objIdrsCapture.isCaptureSelected ())
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
if ( ! bCurrentCaptureForcedFinal )
{
m_objImageQualityBar.setProgress(iCaptureQuality);
}
if ( bCurrentCaptureSelectedFinal )
{
m_objDocumentAreaView.setCaptureValidated();
}
m_objImageQualityBar.invalidate();
m_objCameraView.invalidate();
}
});
if ( bCurrentCaptureSelected )
{
final String strSelectedImagePath = CPathProvider.getInternalPathSelectedImage ();
argWorker.saveSelectedCapture ( strSelectedImagePath );
final Intent objCaptureCorrectionIntent = new Intent ( CCaptureActivity.this, CAdjustmentActivity.class );
objCaptureCorrectionIntent.putExtra ( "EXTRA_CAPTURED_IMAGE", strSelectedImagePath );
if ( argDocumentCorners.bCornersFound )
{
objCaptureCorrectionIntent.putExtra ( "EXTRA_DETECTED_CORNERS", argDocumentCorners.xiCorners );
}
CCaptureActivity.this.startActivity ( objCaptureCorrectionIntent );
}
}
}
}
finally
{
// Unlock the worker before exiting
argWorker.unlock ();
}
}
}
}
/**
* Setup the listener class that links the view to the camera.
*/
private void setupCameraViewListener ()
{
m_objCameraView.setSurfaceTextureListener ( new TextureView.SurfaceTextureListener ()
{
/**
* Surface texture available handler.
* @param argSurfaceTexture The surface texture (unused)
* @param iWidth Surface texture width (unused)
* @param iHeight Surface texture height (unused)
*/
@Override
public void onSurfaceTextureAvailable ( final SurfaceTexture argSurfaceTexture, final int iWidth, final int iHeight )
{
// No need to use the provided parameters - simply open the camera.
openCamera ();
}
@Override
public void onSurfaceTextureSizeChanged ( final SurfaceTexture argSurfaceTexture, final int iWidth, final int iHeight )
{
}
@Override
public boolean onSurfaceTextureDestroyed ( final SurfaceTexture argSurfaceTexture )
{
return true;
}
@Override
public void onSurfaceTextureUpdated ( final SurfaceTexture argSurfaceTexture )
{
}
});
}
/**
* Setup the camera status callback listener.
*/
private void setupCameraStatusCallback ()
{
m_objCameraStateCallback = new CameraDevice.StateCallback ()
{
/**
* Camera open handler.
* @param argCameraDevice The camera opened.
*/
@Override
public void onOpened ( final CameraDevice argCameraDevice )
{
m_objCameraDevice = argCameraDevice;
startCamera ();
}
@Override
public void onDisconnected ( final CameraDevice argCameraDevice )
{
}
@Override
public void onError ( final CameraDevice argCameraDevice, final int iError )
{
if ( m_objCameraDevice != null && m_objCameraDevice.getId ().equals ( argCameraDevice.getId ()))
{
Log.e ( "CCaptureActivity", "The camera encountered an error: " + iError );
}
}
};
}
private void getCamera ()
{
try
{
// Parse all available cameras and select the first rear-facing found.
m_strCameraId = null;
CameraCharacteristics objCameraCharacteristics = null;
final String[] xstrCameraIds = m_objCameraManager.getCameraIdList ();
for ( final String strCurrentCameraId : xstrCameraIds )
{
objCameraCharacteristics = m_objCameraManager.getCameraCharacteristics ( strCurrentCameraId );
if ( objCameraCharacteristics.get ( CameraCharacteristics.LENS_FACING ) == CameraCharacteristics.LENS_FACING_BACK )
{
m_strCameraId = strCurrentCameraId;
break;
}
}
if (m_strCameraId == null)
{
Log.e("CCaptureActivity", "Could not find device back camera");
}
final StreamConfigurationMap objStreamConfigurationMap = objCameraCharacteristics.get ( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP );
m_iCameraOrientation = objCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Finally, retrieve the capture and preview sizes.
m_objCaptureSize = selectCaptureSize ( objStreamConfigurationMap.getOutputSizes ( ImageFormat.YUV_420_888 ), m_iCameraOrientation );
m_objPreviewSize = selectPreviewSize ( objStreamConfigurationMap.getOutputSizes ( SurfaceTexture.class ), m_objCaptureSize );
Log.i ("CCaptureActivity", "Capture size selected: " + m_objCaptureSize.getHeight () + " x " + m_objCaptureSize.getWidth ());
m_objIdrsCapture.setCharacteristics ( m_objCaptureSize, m_iCameraOrientation );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred while retrieving the device camera", argException );
}
}
private void openCamera ()
{
try
{
// Start or restart the preview handler if needed
if ( ! m_objPreviewThread.isAlive() || m_objPreviewThread.isInterrupted ())
{
m_objPreviewThread.start();
}
m_objPreviewThreadHandler = new Handler ( m_objPreviewThread.getLooper ());
m_objImageReader = ImageReader.newInstance ( m_objCaptureSize.getWidth (), m_objCaptureSize.getHeight (), ImageFormat.YUV_420_888, 2 );
m_objImageReader.setOnImageAvailableListener ( m_objPreviewImageListener, m_objPreviewThreadHandler );
m_objDocumentAreaView.setCaptureSize ( m_objCaptureSize, m_iCameraOrientation );
m_objCameraView.setCaptureSize ( m_objCaptureSize );
m_objCameraManager.openCamera ( m_strCameraId, m_objCameraStateCallback,null );
m_bCameraOpen = true;
}
catch ( final SecurityException argSecurityException )
{
Log.e ( "CCaptureActivity", "A security exception occurred while opening the device camera", argSecurityException );
}
catch (final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred while opening the device camera", argException );
}
}
private void startCamera ()
{
if ( m_objCameraDevice == null || ! m_objCameraView.isAvailable () || m_objPreviewSize == null )
{
return;
}
final SurfaceTexture argSurfaceTexture = m_objCameraView.getSurfaceTexture ();
if ( argSurfaceTexture == null )
{
return;
}
argSurfaceTexture.setDefaultBufferSize ( m_objPreviewSize.getWidth (), m_objPreviewSize.getHeight ());
final Surface argSurface = new Surface ( argSurfaceTexture );
try
{
m_objCaptureRequestBuilder = m_objCameraDevice.createCaptureRequest ( CameraDevice.TEMPLATE_PREVIEW );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred when creating the capture request", argException );
}
m_objCaptureRequestBuilder.addTarget ( argSurface );
m_objCaptureRequestBuilder.addTarget ( m_objImageReader.getSurface ());
try
{
m_objCameraDevice.createCaptureSession ( Arrays.asList ( argSurface, m_objImageReader.getSurface ()),
new CameraCaptureSession.StateCallback ()
{
@Override
public void onConfigured ( final CameraCaptureSession argCameraCaptureSession )
{
m_objCameraCaptureSession = argCameraCaptureSession;
onCaptureSessionConfigured ();
}
@Override
public void onConfigureFailed ( final CameraCaptureSession argCameraCaptureSession )
{
Log.e ("CCaptureActivity", "The camera capture session could not be successfully created." );
}
},
null );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred when creating the capture session", argException );
}
}
/**
* Callback that will start capture session once it is configured.
*/
private void onCaptureSessionConfigured ()
{
if ( m_objCameraDevice == null )
{
return;
}
m_objCaptureRequestBuilder.set ( CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO );
try
{
m_objCameraCaptureSession.setRepeatingRequest ( m_objCaptureRequestBuilder.build (),
m_objHardwareStatus,
m_objPreviewThreadHandler );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occured while starting capture session", argException );
}
}
private void closeCamera ()
{
if ( m_bCameraOpen )
{
m_objCameraDevice.close ();
m_bCameraOpen = false;
}
if( m_objCameraCaptureSession != null )
{
m_objCameraCaptureSession.close();
}
}
private Size selectCaptureSize ( final Size [] xargSizes, final int iCameraOrientation )
{
// Retrieve the screen dimensions to know its aspect ratio
final DisplayMetrics objDisplayMetrics = new DisplayMetrics ();
getWindowManager().getDefaultDisplay ().getMetrics ( objDisplayMetrics );
final float fScreenRatio = (float) objDisplayMetrics.widthPixels / objDisplayMetrics.heightPixels;
Size objMaxSizeSameRatio = null;
Size objMaxSizeAnyRatio = null;
// Now iterates on the list to find the largest (in area) below the accepted limit
for (final Size objCurrent : xargSizes )
{
final int iAreaSize = objCurrent.getHeight () * objCurrent.getWidth ();
final float fSizeRatio;
if ( iCameraOrientation == 0 || iCameraOrientation == 180)
{
fSizeRatio = (float) objCurrent.getWidth () / objCurrent.getHeight ();
}
else
{
fSizeRatio = (float) objCurrent.getHeight () / objCurrent.getWidth ();
}
if ( iAreaSize < CAPTURE_SIZE_MAX_PIXELS )
{
// Search with same ratio
if ( fSizeRatio == fScreenRatio &&
( objMaxSizeSameRatio == null || ( objMaxSizeSameRatio.getWidth () * objMaxSizeSameRatio.getHeight () < iAreaSize )))
{
objMaxSizeSameRatio = objCurrent;
}
// Search as well without taking the ratio into account
if ( objMaxSizeAnyRatio == null || ( objMaxSizeAnyRatio.getWidth () * objMaxSizeAnyRatio.getHeight () < iAreaSize ))
{
objMaxSizeAnyRatio = objCurrent;
}
}
}
return objMaxSizeSameRatio != null ? objMaxSizeSameRatio : objMaxSizeAnyRatio;
}
公共类CCaptureActivity扩展了AppCompativity
{
/**
*活动创建处理程序。
*@param argSavedInstanceState实例在上一个会话期间保存(未使用)。
*/
@凌驾
创建时受保护的void(最终绑定argSavedInstanceState)
{
super.onCreate(argSavedInstanceState);
//获取将在活动运行时以编程方式更新的UI元素。
setContentView(R.layout.activity_捕获);
m_objDocumentAreaView=(CDocumentAreaView)findviewbyd(R.id.corners_视图);
m_objCameraView=(CCameraView)findViewById(R.id.camera_视图);
//选择要使用和初始化的摄影机及其预览和所需的处理程序。
m_objPreviewImageListener=新的CCaptureAnalysisRunner();
setupCameraViewListener();
setupCameraStatusCallback();
m_objPreviewThread=新的HandlerThread(“PreviewUpdate”);
m_objCameraManager=(CameraManager)getSystemService(Context.CAMERA_服务);
getCamera();
m_objHardwareStatus.onCreate(本);
}
@凌驾
恢复时受保护的无效()
{
super.onResume();
m_objHardwareStatus.onResume();
m_objidrscature.onResume(本文件);
openCamera();
}
@凌驾
受保护的void onPause()
{
m_objIdrsCapture.onPause();
m_objHardwareStatus.onPause();
闭式摄像机();
super.onPause();
}
私有类CCaptureAnalysisRunner实现ImageReader.OnImageAvailableListener
{
公共无效onImageAvailable(最终图像阅读器argImageReader)
{
最终图像objCapturedImage=argImageReader.acquireLatestImage();
//图像有时可能为空,因此在这种情况下跳过处理
if(null!=objCapturedImage)
{
最终布尔值bDocumentExposureOk=m_objHardwareStatus.isExposureOk();
最终布尔值bCameraFocusSet=(bDocumentExposureOk&m_objHardwareStatus.isFocusSet());
最终布尔值bDeviceStable=(bCameraFocusSet&m_objHardwareStatus.isDeviceStable());
final cidrscapt.CWorker objWorker=((bDeviceStable | | | m| u bForceCapture)?m_objidrscature.tryLock():null);
if(objWorker!=null)
{
Log.i(“CCaptureActivity”,“图像可用并将被处理”);
objWorker.setCurrentCapture(objCapturedImage);
objCapturedImage.close();
AsyncTask.execute(新的可运行()
{
@凌驾
公开作废运行()
{
onImageAnalysisCompleted(objWorker,objWorker.detectDocumentCorners());
}
});
}
其他的
{
objCapturedImage.close();
}
//在任何情况下,都必须更新指标
runOnUiThread(新的可运行()
{
@凌驾
公开作废运行()
{
if(m_objDocumentAreaView.reduceIntensity())
{
m_objCornersFlag.setChecked(false);
m_objAreaFlag.setChecked(false);
}
m_objeexposureflag.setChecked(bDocumentExposureOk);
m_objFocusFlag.setChecked(bCameraFocusSet);
m_objStabilityFlag.setChecked(bDeviceStable);
m_objDocumentAreaView.invalidate();
m_objeexposureflag.invalidate();
m_objFocusFlag.invalidate();
m_objStabilityFlag.invalidate();
}
});
}
}
私有void onImageAnalysisCompleted(最终CIdrsCapture.CWorker argWorker,最终CIdrsCapture.DocumentCorners argDocumentCorners)
{
如果(!m_objidrscature.isCaptureSelected())
{
runOnUiThread(新的Runnable()
{
@凌驾
公开募捐
{
m_objCornersFlag.setChecked(argDocumentCorners.bCornersFound);
m_objAreaFlag.setChecked(argDocumentCorners.bTargetAreaOk);
if(argDocumentCorners.bCornersFound)
{
m_objDocumentAreaView.setDetectedCorners(argDocumentCorners.xicorner,argDocumentCorners.bTargetAreaOk);
}
m_objDocumentAreaView.invalidate();
m_objCornersFlag.invalidate();
m_objAreaFlag.invalidate();
}
});
尝试
{
if((argDocumentCorners.bCornersFound&&argDocumentCorners.bTargetAreaOk)| | m| bForceCapture)
{
final int iCaptureQuality=m_bForceCapture?100:argWorker.evaluateQuality();
布尔bCurrentCaptureSelected=false;
布尔bCurrentCaptureForced=false;
已同步(m_objCaptureSelectionLock)
{
如果(iCaptureQuality>=CAPTURE_QUALITY_THRESHOLD&&!m_objidrscature.isCaptureSelected())
{
argWorker.selectCapture();
bCurrentCaptureSelected=true;
如果(m_b力容)
{
bCurrentCaptureForced=真;
m_bForceCapture=假;
}
}
}
//仅当当前未选择捕获或此捕获是选定的捕获时,才更新控件
最终布尔值bCurrentCaptureSelectedFinal=bCurrentCaptureSelected;
最终布尔值bCurrentCaptureForcedFinal=bCurrentCaptureForced;
如果(bCurrentCaptureSelected | | |!m_objidrscature.isCaptureSelected())
{
runOn
public class CCaptureActivity extends AppCompatActivity
{
/**
* Activity creation handler.
* @param argSavedInstanceState Instance saved during previous session (unused).
*/
@Override
protected void onCreate ( final Bundle argSavedInstanceState )
{
super.onCreate ( argSavedInstanceState );
// Fetch the UI elements which will be updated programatically during activity runtime.
setContentView ( R.layout.activity_capture );
m_objDocumentAreaView = (CDocumentAreaView) findViewById ( R.id.corners_view );
m_objCameraView = (CCameraView) findViewById ( R.id.camera_view );
// Select the camera to use and initialize it as well as its preview and the needed handlers.
m_objPreviewImageListener = new CCaptureAnalysisRunner ();
setupCameraViewListener ();
setupCameraStatusCallback ();
m_objPreviewThread = new HandlerThread ( "PreviewUpdate" );
m_objCameraManager = (CameraManager) getSystemService ( Context.CAMERA_SERVICE );
getCamera ();
m_objHardwareStatus.onCreate ( this );
}
@Override
protected void onResume ()
{
super.onResume ();
m_objHardwareStatus.onResume ();
m_objIdrsCapture.onResume ( this );
openCamera ();
}
@Override
protected void onPause ()
{
m_objIdrsCapture.onPause ();
m_objHardwareStatus.onPause ();
closeCamera ();
super.onPause ();
}
private class CCaptureAnalysisRunner implements ImageReader.OnImageAvailableListener
{
public void onImageAvailable ( final ImageReader argImageReader )
{
final Image objCapturedImage = argImageReader.acquireLatestImage ();
// The image may be null sometimes, so skip processing in such case
if ( null != objCapturedImage )
{
final boolean bDocumentExposureOk = m_objHardwareStatus.isExposureOk ();
final boolean bCameraFocusSet = ( bDocumentExposureOk && m_objHardwareStatus.isFocusSet ());
final boolean bDeviceStable = ( bCameraFocusSet && m_objHardwareStatus.isDeviceStable ());
final CIdrsCapture.CWorker objWorker = (( bDeviceStable || m_bForceCapture ) ? m_objIdrsCapture.tryLock () : null );
if ( objWorker != null )
{
Log.i ( "CCaptureActivity", "An image is available and will be processed" );
objWorker.setCurrentCapture ( objCapturedImage );
objCapturedImage.close ();
AsyncTask.execute ( new Runnable ()
{
@Override
public void run ()
{
onImageAnalysisCompleted ( objWorker, objWorker.detectDocumentCorners ());
}
});
}
else
{
objCapturedImage.close ();
}
// In any case, the indicators must be updated
runOnUiThread ( new Runnable ()
{
@Override
public void run ()
{
if ( m_objDocumentAreaView.reduceIntensity ())
{
m_objCornersFlag.setChecked ( false );
m_objAreaFlag.setChecked ( false );
}
m_objExposureFlag.setChecked ( bDocumentExposureOk );
m_objFocusFlag.setChecked ( bCameraFocusSet );
m_objStabilityFlag.setChecked ( bDeviceStable );
m_objDocumentAreaView.invalidate ();
m_objExposureFlag.invalidate ();
m_objFocusFlag.invalidate ();
m_objStabilityFlag.invalidate ();
}
});
}
}
private void onImageAnalysisCompleted (final CIdrsCapture.CWorker argWorker, final CIdrsCapture.DocumentCorners argDocumentCorners)
{
if ( ! m_objIdrsCapture.isCaptureSelected ())
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
m_objCornersFlag.setChecked(argDocumentCorners.bCornersFound);
m_objAreaFlag.setChecked(argDocumentCorners.bTargetAreaOk);
if (argDocumentCorners.bCornersFound)
{
m_objDocumentAreaView.setDetectedCorners(argDocumentCorners.xiCorners, argDocumentCorners.bTargetAreaOk);
}
m_objDocumentAreaView.invalidate();
m_objCornersFlag.invalidate();
m_objAreaFlag.invalidate();
}
});
try
{
if (( argDocumentCorners.bCornersFound && argDocumentCorners.bTargetAreaOk ) || m_bForceCapture )
{
final int iCaptureQuality = m_bForceCapture ? 100 : argWorker.evaluateQuality ();
boolean bCurrentCaptureSelected = false;
boolean bCurrentCaptureForced = false;
synchronized ( m_objCaptureSelectionLock )
{
if (iCaptureQuality >= CAPTURE_QUALITY_THRESHOLD && ! m_objIdrsCapture.isCaptureSelected ())
{
argWorker.selectCapture();
bCurrentCaptureSelected = true;
if ( m_bForceCapture )
{
bCurrentCaptureForced = true;
m_bForceCapture = false;
}
}
}
// Update the controls only if no capture are currently selected or if this capture is the one selected
final boolean bCurrentCaptureSelectedFinal = bCurrentCaptureSelected;
final boolean bCurrentCaptureForcedFinal = bCurrentCaptureForced;
if ( bCurrentCaptureSelected || ! m_objIdrsCapture.isCaptureSelected ())
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
if ( ! bCurrentCaptureForcedFinal )
{
m_objImageQualityBar.setProgress(iCaptureQuality);
}
if ( bCurrentCaptureSelectedFinal )
{
m_objDocumentAreaView.setCaptureValidated();
}
m_objImageQualityBar.invalidate();
m_objCameraView.invalidate();
}
});
if ( bCurrentCaptureSelected )
{
final String strSelectedImagePath = CPathProvider.getInternalPathSelectedImage ();
argWorker.saveSelectedCapture ( strSelectedImagePath );
final Intent objCaptureCorrectionIntent = new Intent ( CCaptureActivity.this, CAdjustmentActivity.class );
objCaptureCorrectionIntent.putExtra ( "EXTRA_CAPTURED_IMAGE", strSelectedImagePath );
if ( argDocumentCorners.bCornersFound )
{
objCaptureCorrectionIntent.putExtra ( "EXTRA_DETECTED_CORNERS", argDocumentCorners.xiCorners );
}
CCaptureActivity.this.startActivity ( objCaptureCorrectionIntent );
}
}
}
}
finally
{
// Unlock the worker before exiting
argWorker.unlock ();
}
}
}
}
/**
* Setup the listener class that links the view to the camera.
*/
private void setupCameraViewListener ()
{
m_objCameraView.setSurfaceTextureListener ( new TextureView.SurfaceTextureListener ()
{
/**
* Surface texture available handler.
* @param argSurfaceTexture The surface texture (unused)
* @param iWidth Surface texture width (unused)
* @param iHeight Surface texture height (unused)
*/
@Override
public void onSurfaceTextureAvailable ( final SurfaceTexture argSurfaceTexture, final int iWidth, final int iHeight )
{
// No need to use the provided parameters - simply open the camera.
openCamera ();
}
@Override
public void onSurfaceTextureSizeChanged ( final SurfaceTexture argSurfaceTexture, final int iWidth, final int iHeight )
{
}
@Override
public boolean onSurfaceTextureDestroyed ( final SurfaceTexture argSurfaceTexture )
{
return true;
}
@Override
public void onSurfaceTextureUpdated ( final SurfaceTexture argSurfaceTexture )
{
}
});
}
/**
* Setup the camera status callback listener.
*/
private void setupCameraStatusCallback ()
{
m_objCameraStateCallback = new CameraDevice.StateCallback ()
{
/**
* Camera open handler.
* @param argCameraDevice The camera opened.
*/
@Override
public void onOpened ( final CameraDevice argCameraDevice )
{
m_objCameraDevice = argCameraDevice;
startCamera ();
}
@Override
public void onDisconnected ( final CameraDevice argCameraDevice )
{
}
@Override
public void onError ( final CameraDevice argCameraDevice, final int iError )
{
if ( m_objCameraDevice != null && m_objCameraDevice.getId ().equals ( argCameraDevice.getId ()))
{
Log.e ( "CCaptureActivity", "The camera encountered an error: " + iError );
}
}
};
}
private void getCamera ()
{
try
{
// Parse all available cameras and select the first rear-facing found.
m_strCameraId = null;
CameraCharacteristics objCameraCharacteristics = null;
final String[] xstrCameraIds = m_objCameraManager.getCameraIdList ();
for ( final String strCurrentCameraId : xstrCameraIds )
{
objCameraCharacteristics = m_objCameraManager.getCameraCharacteristics ( strCurrentCameraId );
if ( objCameraCharacteristics.get ( CameraCharacteristics.LENS_FACING ) == CameraCharacteristics.LENS_FACING_BACK )
{
m_strCameraId = strCurrentCameraId;
break;
}
}
if (m_strCameraId == null)
{
Log.e("CCaptureActivity", "Could not find device back camera");
}
final StreamConfigurationMap objStreamConfigurationMap = objCameraCharacteristics.get ( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP );
m_iCameraOrientation = objCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Finally, retrieve the capture and preview sizes.
m_objCaptureSize = selectCaptureSize ( objStreamConfigurationMap.getOutputSizes ( ImageFormat.YUV_420_888 ), m_iCameraOrientation );
m_objPreviewSize = selectPreviewSize ( objStreamConfigurationMap.getOutputSizes ( SurfaceTexture.class ), m_objCaptureSize );
Log.i ("CCaptureActivity", "Capture size selected: " + m_objCaptureSize.getHeight () + " x " + m_objCaptureSize.getWidth ());
m_objIdrsCapture.setCharacteristics ( m_objCaptureSize, m_iCameraOrientation );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred while retrieving the device camera", argException );
}
}
private void openCamera ()
{
try
{
// Start or restart the preview handler if needed
if ( ! m_objPreviewThread.isAlive() || m_objPreviewThread.isInterrupted ())
{
m_objPreviewThread.start();
}
m_objPreviewThreadHandler = new Handler ( m_objPreviewThread.getLooper ());
m_objImageReader = ImageReader.newInstance ( m_objCaptureSize.getWidth (), m_objCaptureSize.getHeight (), ImageFormat.YUV_420_888, 2 );
m_objImageReader.setOnImageAvailableListener ( m_objPreviewImageListener, m_objPreviewThreadHandler );
m_objDocumentAreaView.setCaptureSize ( m_objCaptureSize, m_iCameraOrientation );
m_objCameraView.setCaptureSize ( m_objCaptureSize );
m_objCameraManager.openCamera ( m_strCameraId, m_objCameraStateCallback,null );
m_bCameraOpen = true;
}
catch ( final SecurityException argSecurityException )
{
Log.e ( "CCaptureActivity", "A security exception occurred while opening the device camera", argSecurityException );
}
catch (final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred while opening the device camera", argException );
}
}
private void startCamera ()
{
if ( m_objCameraDevice == null || ! m_objCameraView.isAvailable () || m_objPreviewSize == null )
{
return;
}
final SurfaceTexture argSurfaceTexture = m_objCameraView.getSurfaceTexture ();
if ( argSurfaceTexture == null )
{
return;
}
argSurfaceTexture.setDefaultBufferSize ( m_objPreviewSize.getWidth (), m_objPreviewSize.getHeight ());
final Surface argSurface = new Surface ( argSurfaceTexture );
try
{
m_objCaptureRequestBuilder = m_objCameraDevice.createCaptureRequest ( CameraDevice.TEMPLATE_PREVIEW );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred when creating the capture request", argException );
}
m_objCaptureRequestBuilder.addTarget ( argSurface );
m_objCaptureRequestBuilder.addTarget ( m_objImageReader.getSurface ());
try
{
m_objCameraDevice.createCaptureSession ( Arrays.asList ( argSurface, m_objImageReader.getSurface ()),
new CameraCaptureSession.StateCallback ()
{
@Override
public void onConfigured ( final CameraCaptureSession argCameraCaptureSession )
{
m_objCameraCaptureSession = argCameraCaptureSession;
onCaptureSessionConfigured ();
}
@Override
public void onConfigureFailed ( final CameraCaptureSession argCameraCaptureSession )
{
Log.e ("CCaptureActivity", "The camera capture session could not be successfully created." );
}
},
null );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occurred when creating the capture session", argException );
}
}
/**
* Callback that will start capture session once it is configured.
*/
private void onCaptureSessionConfigured ()
{
if ( m_objCameraDevice == null )
{
return;
}
m_objCaptureRequestBuilder.set ( CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO );
try
{
m_objCameraCaptureSession.setRepeatingRequest ( m_objCaptureRequestBuilder.build (),
m_objHardwareStatus,
m_objPreviewThreadHandler );
}
catch ( final Exception argException )
{
Log.e ( "CCaptureActivity", "An exception occured while starting capture session", argException );
}
}
private void closeCamera ()
{
if ( m_bCameraOpen )
{
m_objCameraDevice.close ();
m_bCameraOpen = false;
}
if( m_objCameraCaptureSession != null )
{
m_objCameraCaptureSession.close();
}
}
private Size selectCaptureSize ( final Size [] xargSizes, final int iCameraOrientation )
{
// Retrieve the screen dimensions to know its aspect ratio
final DisplayMetrics objDisplayMetrics = new DisplayMetrics ();
getWindowManager().getDefaultDisplay ().getMetrics ( objDisplayMetrics );
final float fScreenRatio = (float) objDisplayMetrics.widthPixels / objDisplayMetrics.heightPixels;
Size objMaxSizeSameRatio = null;
Size objMaxSizeAnyRatio = null;
// Now iterates on the list to find the largest (in area) below the accepted limit
for (final Size objCurrent : xargSizes )
{
final int iAreaSize = objCurrent.getHeight () * objCurrent.getWidth ();
final float fSizeRatio;
if ( iCameraOrientation == 0 || iCameraOrientation == 180)
{
fSizeRatio = (float) objCurrent.getWidth () / objCurrent.getHeight ();
}
else
{
fSizeRatio = (float) objCurrent.getHeight () / objCurrent.getWidth ();
}
if ( iAreaSize < CAPTURE_SIZE_MAX_PIXELS )
{
// Search with same ratio
if ( fSizeRatio == fScreenRatio &&
( objMaxSizeSameRatio == null || ( objMaxSizeSameRatio.getWidth () * objMaxSizeSameRatio.getHeight () < iAreaSize )))
{
objMaxSizeSameRatio = objCurrent;
}
// Search as well without taking the ratio into account
if ( objMaxSizeAnyRatio == null || ( objMaxSizeAnyRatio.getWidth () * objMaxSizeAnyRatio.getHeight () < iAreaSize ))
{
objMaxSizeAnyRatio = objCurrent;
}
}
}
return objMaxSizeSameRatio != null ? objMaxSizeSameRatio : objMaxSizeAnyRatio;
}