I'm working with the camera2 api, and I'm having problems controlling different flash modes.

My code is the following:

private boolean setFlashMode(String flashMode) {
        try {
            switch (flashMode) {
                case "on":
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
                    break;
                case "off":
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                    break;
                case "auto":
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                case "torch":
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                    break;
                default:
                    return false;
            }
            cameraCaptureSession.setRepeatingRequest(
                    captureRequestBuilder.build(), null, null);
            return true;
        } catch (CameraAccessException e) {
            e.printStackTrace();
            return false;
        }
    }

Changing from torch to off back and forward gives no problem, but if I try to set it to on not only it doesn't work, but breaks the setting to torch too.

Now, I've read this and understood that there are different levels for controlling the flash and stuff, but I couldn't wrap my mind around the problem, since it's my first time working with camera2 (I'm adding a functionality to an existing code) and the documentation is not helping.

What am I clearly doing wrong?

EDIT This is how my code looks like after @eddy-talvala answer:

private boolean setFlashMode(String flashMode) {
        try {
            switch (flashMode) {
                case "on":
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
                    break;
                case "off":
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                    break;
                case "auto":
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

                case "torch":
                    captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                    break;
                default:
                    return false;
            }
            cameraCaptureSession.setRepeatingRequest(
                    captureRequestBuilder.build(), null, null);
            return true;
        } catch (CameraAccessException e) {
            e.printStackTrace();
            return false;
        }

    }

Still no luck but I think I have a better understanding of this, even if it doesn't work as desired yet.

In order to be more clear, what I'm trying to achieve is the ability to switch between these modes:

  • on: the flash always fires when I take a picture, regardless the exposure conditions
  • off: the flash never fires when I take a picture
  • auto: based on the exposure conditions, let the system choose wether fire the flash or not
  • torch: keep the flash on when I'm using the camera, even without any picture taken

Switching from torch to off still works, but switching to the others doesn't. auto doesn't fire the flash in low light conditions, and if I switch to auto from torch there's a good chance the flash still stays on like torch. Moreover, switching to on doesn't cause any flash fired when taking a picture.

My "demo" app is a modified version of the camera plugin for Flutter project example, since what I'm trying to do is edit the plugin adding this native feature that I need. Modified means I've added the dart code to call that methods and some buttons to the UI to switch between modes. I still use the plugin "as is" when taking the picture.


Solution 1: Eddy Talvala

For "on",you're setting CONTROL_AE_MODE twice - are you trying to set it to "always flash" or "never flash"? Right now "always flash" is winning.

In general, any of the AE_MODE options with FLASH in the name override FLASH_MODE; if you set AUTO_FLASH, ALWAYS_FLASH, or the REDEYE option, what you set FLASH_MODE to doesn't matter. It only matters for AE_MODE_ON and OFF, in which case FLASH_MODE controls what happens.

That said, you don't really want to use FLASH_MODE_SINGLE anyway (that says "fire flash for this request" so repeating a request like that isn't a good idea) even if it won't actually do anything. Just switch FLASH_MODE between TORCH and OFF.

Also for "off", you're disabling auto-exposure entirely, not just turning off flash. If you don't want to flash to fire, just set AE_MODE to AE_MODE_ON and FLASH_MODE to OFF.

The same goes for "torch" mode.

It's not clear what problem you're running into with "on" - you just say it doesn't work, but hopefully some of the above resolves it.