Android Camera API ISO Setting?

Would anyone know where to control the ISO setting for the camera from in the Android SDK ? It should be possible as the native camera application on the HTC Desire has ISO settings.


Solution 1:

you should take a look at the methods flatten(), unflatten(), get(String key), set(String key, String value) in android.hardware.Camera.Parameters. Also consider the source code of that class. It might make things clearer.

First you need to obtain the Camera.Parameters. Unflatten it to a String and investigate it. I am developing on a HTC Desire as well an get the following String:

sharpness-max=30;zoom=0;taking-picture-zoom=0;zoom-supported=true;sharpness-min=0;sharpness=10;contrast=5;whitebalance=auto;jpeg-quality=100;preview-format-values=yuv420sp;jpeg-thumbnail-quality=75;preview-format=yuv420sp;preview-size=640x480;focal-length=3.53;iso=auto;meter-mode=meter-center;front-camera-mode=mirror;flash-mode-values=off,auto,on,torch;preview-frame-rate-values=15;preview-frame-rate=15;focus-mode-values=auto,infinity;jpeg-thumbnail-width=640;jpeg-thumbnail-size-values=640x480,512x384,384x288,0x0;zoom-ratios=100,114,131,151,174,200;saturation-def=5;preview-size-values=1280x720,800x480,768x432,720x480,640x480,576x432,480x320,400x240,384x288,352x288,320x240,272x272,240x240,240x160,176x144,160x120;smart-contrast=off;picture-size-values=2592x1952,2592x1456,2592x1936,2592x1728,2592x1552,2048x1536,2048x1360,2048x1216,2048x1152,1600x1200,1584x1056,1280x960,1280x848,1280x768,1280x720,1024x768,640x480,640x416,640x384,640x368,512x384,400x400,272x272;contrast-min=0;min-exposure-compensation=-4;brightness-min=0;antibanding=auto;taking-picture-zoom-min=0;saturation-min=1;contrast-max=10;vertical-view-angle=42.5;taking-picture-zoom-max=21;contrast-def=5;brightness-max=6;horizontal-view-angle=54.8;brightness=3;jpeg-thumbnail-height=480;cam-mode=0;focus-mode=auto;sharpness-def=10;front-camera-mode-values=mirror,reverse;picture-format-values=jpeg;saturation-max=10;max-exposure-compensation=4;exposure-compensation=0;exposure-compensation-step=0.5;flash-mode=off;effect-values=none,mono,negative,solarize,sepia,posterize,aqua;meter-mode-values=meter-average,meter-center,meter-spot;picture-size=2592x1952;max-zoom=5;effect=none;saturation=5;whitebalance-values=auto,incandescent,fluorescent,daylight,cloudy-daylight;picture-format=jpeg;brightness-def=3;iso-values=auto,deblur,100,200,400,800,1250;enable-caf=off;antibanding-values=off,50hz,60hz,auto

So basically there is a key called iso-values to retrieve the supported values and a key iso which holds the current value.

You can do the following:

Camera cam = Camera.open();
Camera.Parameters camParams = cam.getParameters();
String supportedIsoValues = camParams.get("iso-values"); //supported values, comma separated String
camParams.set("iso", (String)newValue);
cam.setParameters(camParams);

And with reference to the unflattened parameters I would assume that there is a difference between the iso and exposure compensation settings.

Solution 2:

By now (KK 4.4.2) android has no official APIs to manage ISO.
ISO management is a totally device dependant matter, and 8/18 devices i tested so far doesn't support ISO settings at all.
Investigate Camera.getParameters().flatten() String to check valid keywords, every device can use different keywords!!
Most devices use "iso-values" keyword to define a comma separated list-of-possible-values to use with "iso" keyword, like this:

param.set("iso", valid_value_from_list);

Some other devices uses "iso-mode-values" and "iso" keywords (Galaxy Nexus).
I found also a device that uses "iso-speed-values" and "iso-speed" (Micromax A101).
Another one that make me sad is "nv-picture-iso-values" -> "nv-picture-iso" (LG dual P990).

Follow szia answer on how to use these keywords.

Here's some code i use to get a list of valid values using known keywords:

String flat = param.flatten();
String[] isoValues = null;
String values_keyword=null;
String iso_keyword=null;
if(flat.contains("iso-values")) {
    // most used keywords
    values_keyword="iso-values";
    iso_keyword="iso";
} else if(flat.contains("iso-mode-values")) {
    // google galaxy nexus keywords
    values_keyword="iso-mode-values";
    iso_keyword="iso";
} else if(flat.contains("iso-speed-values")) {
    // micromax a101 keywords
    values_keyword="iso-speed-values";
    iso_keyword="iso-speed";
} else if(flat.contains("nv-picture-iso-values")) {
    // LG dual p990 keywords
    values_keyword="nv-picture-iso-values";
    iso_keyword="nv-picture-iso";
}
// add other eventual keywords here...
if(iso_keyword!=null) {
    // flatten contains the iso key!!
    String iso = flat.substring(flat.indexOf(values_keyword));
    iso = iso.substring(iso.indexOf("=")+1);

    if(iso.contains(";")) iso = iso.substring(0, iso.indexOf(";"));

    isoValues = iso.split(",");

} else {
    // iso not supported in a known way
}

Solution 3:

since I had the same problem of finding if the device has an ISO parameter I looked at this answer https://stackoverflow.com/a/23567103/3976589 and saw that @j.c had solved the problem for 8/18 devices by listing some parameters that he had found on different devices. Based on that listing I found that each paramter contains the words iso and values (sometimes only those words, sometimes something additional).

So if I list all of the camera parameters and search for a strings that contain both words I will know what is the name of the ISO parameter, if it exists. Furthermore if the parameter exists I can take the supported ISO values and if I want to set one of those values i.e. change the camera parameter, I can just remove the -values at the end of the iso-values parameter and then I can change the ISO value successfully.

I will now share my code for this task. First a snippet that retrieves a list with supported ISO values.

    private String ISOValuesParameter = null;
    private String ISOParameter = null;
    private String ISOValues = null;


    private void initCamera() {
        Camera mCamera = Camera.open();

        // this will list supported values
        String ISOvalues = getISOValues(); 
        textViewISO = (TextView) findViewById(R.id.viewISO);
        textViewISO.setText(ISOvalues);

    // setting Minimum ISO value
    if(ISOValuesParameter != null) {
        Camera.Parameters params = mCamera.getParameters();

        ISOParameter = ISOValuesParameter.replace("-values", "");
        params.set(ISOParameter, getMinISO());

        mCamera.setParameters(params);

        // get the updated ISO value
        params = mCamera.getParameters();

        String ISO = params.get(ISOParameter);

        Toast.makeText(this,"ISO set to: " + ISO, Toast.LENGTH_SHORT).show();
    }

    }

    // returns a list with supported ISO values
    private String getISOValues() {
            ISOValuesParamter = getISOValuesParameter();
            Camera.Parameters params = mCamera.getParameters();
            ISOValues = params.get(ISOValuesParamter);

            return ISOValues!=null ? ISOValues : "ISO not supported";
    }

    // this will return the name of the ISO parameter containing supported ISO values
    private String getISOValuesParameter() {
            Camera.Parameters params = mCamera.getParameters();

            String flatten = params.flatten();
            String[] paramsSeparated = flatten.split(";");
            for(String cur : paramsSeparated) {
                if(cur.contains("iso") && cur.contains("values")) {
                    return cur.substring(0,cur.indexOf('='));
                }
            }

            return null;
    }

This snippet only lists the supported ISO values. In my application I needed to pick the lowest ISO. Here is my solution:

private String getMinISO() {
    if(ISOValues == null) {
        return null;
    }

    String[] ISOarray = ISOValues.split(",");
    Arrays.sort(ISOarray, myComparator);

    String minISO = ISOarray[ISOarray.length-1];

    return minISO;
}

Here myComparator is a class that compares two strings and sorts the array in descending order. All alphabet words are at the beginning and all numbers are at the end. Here is my implementation:

// Singelton class
public class MyComparator implements  Comparator<String> {

private static MyComparator myComparator = null;

private MyComparator() {}

@Override
public int compare(String a, String b) {
    return compareString(a,b);
}

public static int compareString(String a, String b) {
    if (a.length() > b.length())
        return -1;
    if (a.length() == b.length()) {
        if (a.compareTo(b) > 0)
            return -1;
        else if (a.compareTo(b) == 0)
            return 0;
    }

    return 1;
}

public static synchronized MyComparator getInstance() {
    if(myComparator==null) {
        myComparator = new MyComparator();
    }

    return myComparator;
}

}

I hope my answer helps other people. :)

Cheers! @ee3509