Why does the continuous autofocus camera with the processor not allow switching the camera flash?

What i have done so far:

I have a custom qr code reader camera that should continue to focus the camera for better qr reading.

My problem is that I use the camera flash handler on the \ off button to focus every second, it doesn’t work, or it takes too much time to turn the camera flash on and off. Everything works fine when I delete the auto focus code of the camera every second (Runnable and handler).

I want to automatically and quickly focus when the camera moves, and can also quickly and quickly turn the flash on and off without using Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE , because it is not available for API<14 .

I used Camera.Parameters.FOCUS_MODE_AUTO , but its only focusing of the camera once started, so I used a handler to focus the camera every second.

Min SDK Project version - 9.

My camera activity

 public class CameraActivityNew extends Activity implements OnClickListener, Camera.PreviewCallback { CameraPreviewNew mPreview; FrameLayout flCameraPreview; ImageButton ibFlashButton; Boolean isFlashOn = false; Camera mCamera; private Handler mAutoFocusHandler; private boolean mPreviewing = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); mAutoFocusHandler = new Handler(); setContentView(R.layout.activity_camera); findSetupViews(); mPreview = new CameraPreviewNew(getApplicationContext(), this, autoFocusCB); flCameraPreview.addView(mPreview); } private Runnable doAutoFocus = new Runnable() { public void run() { if (mCamera != null && mPreviewing) { mCamera.autoFocus(autoFocusCB); } } }; Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { mAutoFocusHandler.postDelayed(doAutoFocus, 1000); } }; @Override protected void onResume() { super.onResume(); try { mCamera = Camera.open(); if (mCamera == null) { return; } } catch (Exception e) { e.printStackTrace(); return; } mPreview.setCamera(mCamera); mPreview.showSurfaceView(); mPreviewing = true; } @Override protected void onPause() { super.onPause(); if (mCamera != null) { mPreview.setCamera(null); mCamera.cancelAutoFocus(); mCamera.setPreviewCallback(null); mCamera.stopPreview(); mCamera.release(); mPreview.hideSurfaceView(); mPreviewing = false; mCamera = null; } } private void findSetupViews() { flCameraPreview = (FrameLayout) findViewById(R.id.flCameraPreview); ibFlashButton = (ImageButton) findViewById(R.id.ibFlash); ibFlashButton.setOnClickListener(this); if (getPackageManager().hasSystemFeature( PackageManager.FEATURE_CAMERA_FLASH)) { ibFlashButton.setVisibility(View.VISIBLE); ibFlashButton.setOnClickListener(this); } else { ibFlashButton.setVisibility(View.GONE); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.ibFlash: if (isFlashOn) { mPreview.setCameraFlashLight(false); isFlashOn = false; ibFlashButton.setImageResource(R.drawable.flashoff); } else { mPreview.setCameraFlashLight(true); ibFlashButton.setImageResource(R.drawable.flashon); isFlashOn = true; } break; } } @Override public void onPreviewFrame(final byte[] data, final Camera camera) { // processed here qr code and works fine if camera focus //now removed to narrow the code for posting the question } } 

And the camera preview class:

 public class CameraPreviewNew extends ViewGroup implements Callback { public static final int CAMERA_BACK = 0; public static final int CAMERA_FRONT = 1; public Camera mCamera = null; private Context context = null; SurfaceView mSurfaceView; SurfaceHolder mSurfaceHolder; Size mPreviewSize; List<Size> mSupportedPreviewSizes; PreviewCallback mPreviewCallback; AutoFocusCallback mAutoFocusCallback; public CameraPreviewNew(Context context, PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) { super(context); mPreviewCallback = previewCallback; mAutoFocusCallback = autoFocusCb; this.context = context; mSurfaceView = new SurfaceView(context); addView(mSurfaceView); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } } public void setCamera(Camera camera) { mCamera = camera; if (mCamera != null) { mSupportedPreviewSizes = mCamera.getParameters() .getSupportedPreviewSizes(); requestLayout(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); } public void hideSurfaceView() { mSurfaceView.setVisibility(View.INVISIBLE); } public void showSurfaceView() { mSurfaceView.setVisibility(View.VISIBLE); } public void surfaceCreated(SurfaceHolder holder) { try { if (mCamera != null) { mCamera.setPreviewDisplay(holder); } } catch (IOException exception) { Log.e("logtag", "IOException caused by setPreviewDisplay()", exception); } } public void surfaceDestroyed(SurfaceHolder holder) { if (mCamera != null) { mCamera.cancelAutoFocus(); mCamera.stopPreview(); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null) { return; } if (mCamera != null) { Camera.Parameters parameters = mCamera.getParameters(); mPreviewSize = getBestPreviewSize(mCamera.getParameters(), w, h); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); mCamera.setParameters(parameters); mCamera.setPreviewCallback(mPreviewCallback); mCamera.startPreview(); mCamera.autoFocus(mAutoFocusCallback); setCameraDisplayOrientation(0); } } private void setCameraDisplayOrientation(int cameraId) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); int rotation = ((WindowManager) context .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay() .getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { result = (info.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror } else { // back-facing result = (info.orientation - degrees + 360) % 360; } mCamera.setDisplayOrientation(result); } protected static Comparator<Size> newSizeComparator() { return new Comparator<Size>() { @Override public int compare(Size lhs, Size rhs) { return Integer.valueOf(rhs.height * rhs.width).compareTo( lhs.height * lhs.width); } }; } private Size getBestPreviewSize(Parameters parameters, int screenWidth, int screenHeight) { List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); Collections.sort(supportedSizes, newSizeComparator()); int previewHeight = screenHeight; int previewWidth = screenWidth; if (previewHeight > previewWidth) { int swap = previewWidth; previewWidth = previewHeight; previewHeight = swap; } Size bestSize = null; float bestRatio = 999; for (Size s : supportedSizes) { if (s.height > s.width) { int swap = s.width; s.width = s.height; s.height = swap; } float cameraRatio = ((float) s.height / (float) s.width); float screenRatio = ((float) previewHeight) / ((float) previewWidth); if ((s.height >= previewHeight) && (s.width >= previewWidth)) { float ratioDiff = cameraRatio - screenRatio; if ((ratioDiff < 0.19) && (ratioDiff > -0.19) && (Math.abs(bestRatio) > Math.abs(ratioDiff))) { bestSize = s; bestRatio = ratioDiff; } } } return bestSize; } public void setCameraFlashLight(Boolean setFlash) { Parameters _parameters = mCamera.getParameters(); if (setFlash) { _parameters.setFlashMode(Parameters.FLASH_MODE_TORCH); } else { _parameters.setFlashMode(Parameters.FLASH_MODE_OFF); } mCamera.setParameters(_parameters); mCamera.startPreview(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed && getChildCount() > 0) { final View child = getChildAt(0); final int width = r - l; final int height = b - t; int previewWidth = width; int previewHeight = height; if (mPreviewSize != null) { previewWidth = mPreviewSize.width; previewHeight = mPreviewSize.height; } if (width * previewHeight > height * previewWidth) { final int scaledChildWidth = previewWidth * height / previewHeight; child.layout((width - scaledChildWidth) / 2, 0, (width + scaledChildWidth) / 2, height); } else { final int scaledChildHeight = previewHeight * width / previewWidth; child.layout(0, (height - scaledChildHeight) / 2, width, (height + scaledChildHeight) / 2); } } } } 
+5
android android camera
Jul 31. '15 at 8:46
source share
3 answers

I see some problems with your AutoFocus processing code.
Analysis result

There is a loop in your autofocus.

Explanation

a) The camera preview class mAutoFocusCallback set using autoFocusCb Camera Activity .

  public CameraPreviewNew(Context context,...,AutoFocusCallback autoFocusCb) { super(context); mAutoFocusCallback = autoFocusCb; ... } 

b) surfaceChanged is called once during activity loading. The camera requires autofocus.

  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (mCamera != null) { ... mCamera.startPreview(); /*Auto focus camera and call <code>mAutoFocusCallback</code> after autofocus.*/ mCamera.autoFocus(mAutoFocusCallback); ... } } 

c) Upon completion of autofocus, the mAutoFocusCallback callback is called. mAutoFocusCallback->autoFocusCb->onAutoFocus()
Camera activity

  Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { mAutoFocusHandler.postDelayed(doAutoFocus, 1000); } }; 

d) onAutoFocus assigns another autofocus after 1000 milliseconds, 1 second.
Camera activity

  public void onAutoFocus(boolean success, Camera camera) { mAutoFocusHandler.postDelayed(doAutoFocus, 1000); } 

e) After one second, messages are sent to the handler, which calls the current doAutoFocus requesting camera for auto focus , similar to b) above.

  private Runnable doAutoFocus = new Runnable() { public void run() { if (mCamera != null && mPreviewing) { mCamera.autoFocus(autoFocusCB); } } }; 

f) After autofocus is autoFocusCb , autoFocusCb similar to c) is called again . and the cycle continues.

  Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { mAutoFocusHandler.postDelayed(doAutoFocus, 1000); } }; 

Decision

I am confused why such an implementation. This cycle may cause you to not listen to the flash on / off calls. You need to remove the code below and do something meaningful, otherwise leave onAutoFocus () empty.

 Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { /*REMOVE LINE BELOW*/ mAutoFocusHandler.postDelayed(doAutoFocus, 1000); } }; 

To automatically focus with each movement of the camera, you need to use the motion sensors that came with the phone. You can google it

Hope this helps. Happy coding ...

+5
Aug 07 '15 at 20:38
source share

It seems you do not need to use AutoFocusCallBack for your application because you did nothing more than delay 1 second .

What can you do to focus all the time using FOCUS_MODE_CONTINUOUS_PICTURE (read here ), like this (the setFocus method is in CameraPreview , not in Activity ):

 public void setFocus() { Camera.Parameters p = mCamera.getParameters(); p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); mCamera.setParameters(p); mCamera.startPreview(); } 

And name it in SurfaceChanged :

 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); // You need to choose the most appropriate previewSize for your app Camera.Size previewSize = previewSizes.get(0); parameters.setPreviewSize(previewSize.width, previewSize.height); parameters.setRotation(90); mCamera.setParameters(parameters); mCamera.startPreview(); setFlash(true); setZoomLevel(5); setFocus(); Log.w(TAG, "surfaceChanged()"); } 

For flash you can use this method from CameraPreview :

 public void setFlash(boolean isFlashOn) { Camera.Parameters p = mCamera.getParameters(); if (isFlashOn) { p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); mCamera.setParameters(p); mCamera.startPreview(); } else { p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); mCamera.setParameters(p); mCamera.startPreview(); } Log.w(TAG, "setFlash()"); } 

Hope this helps you! If you have any questions about my answer, feel free to comment.

+4
Jul 31 '15 at 9:25
source share

Although it should be late if you switch camera settings, it is preferable to perform the sequence of operations as shown below

 mCamera.stopPreview(); mCamera.setParameters(params); // set flash on in Camera parameters mCamera.startPreview(); 
0
Feb 13 '18 at 16:03
source share



All Articles