FileDocCategorySizeDatePackage
CameraManager.javaAPI DocAndroid 5.1 API36555Thu Mar 12 22:22:10 GMT 2015android.hardware.camera2

CameraManager

public final class CameraManager extends Object

A system service manager for detecting, characterizing, and connecting to {@link CameraDevice CameraDevices}.

You can get an instance of this class by calling {@link android.content.Context#getSystemService(String) Context.getSystemService()}.

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

For more details about communicating with camera devices, read the Camera developer guide or the {@link android.hardware.camera2 camera2} package documentation.

Fields Summary
private static final String
TAG
private final boolean
DEBUG
private static final int
USE_CALLING_UID
private static final int
API_VERSION_1
private static final int
API_VERSION_2
private ArrayList
mDeviceIdList
private final android.content.Context
mContext
private final Object
mLock
Constructors Summary
public CameraManager(android.content.Context context)

hide


          
       
        DEBUG = Log.isLoggable(TAG, Log.DEBUG);
        synchronized(mLock) {
            mContext = context;
        }
    
Methods Summary
public CameraCharacteristicsgetCameraCharacteristics(java.lang.String cameraId)

Query the capabilities of a camera device. These capabilities are immutable for a given camera.

param
cameraId The id of the camera device to query
return
The properties of the given camera
throws
IllegalArgumentException if the cameraId does not match any known camera device.
throws
CameraAccessException if the camera is disabled by device policy, or the camera device has been disconnected.
throws
SecurityException if the application does not have permission to access the camera
see
#getCameraIdList
see
android.app.admin.DevicePolicyManager#setCameraDisabled

        CameraCharacteristics characteristics = null;

        synchronized (mLock) {
            if (!getOrCreateDeviceIdListLocked().contains(cameraId)) {
                throw new IllegalArgumentException(String.format("Camera id %s does not match any" +
                        " currently connected camera device", cameraId));
            }

            int id = Integer.valueOf(cameraId);

            /*
             * Get the camera characteristics from the camera service directly if it supports it,
             * otherwise get them from the legacy shim instead.
             */

            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
            if (cameraService == null) {
                throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                        "Camera service is currently unavailable");
            }
            try {
                if (!supportsCamera2ApiLocked(cameraId)) {
                    // Legacy backwards compatibility path; build static info from the camera
                    // parameters
                    String[] outParameters = new String[1];

                    cameraService.getLegacyParameters(id, /*out*/outParameters);
                    String parameters = outParameters[0];

                    CameraInfo info = new CameraInfo();
                    cameraService.getCameraInfo(id, /*out*/info);

                    characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
                } else {
                    // Normal path: Get the camera characteristics directly from the camera service
                    CameraMetadataNative info = new CameraMetadataNative();

                    cameraService.getCameraCharacteristics(id, info);

                    characteristics = new CameraCharacteristics(info);
                }
            } catch (CameraRuntimeException e) {
                throw e.asChecked();
            } catch (RemoteException e) {
                // Camera service died - act as if the camera was disconnected
                throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                        "Camera service is currently unavailable", e);
            }
        }
        return characteristics;
    
public java.lang.String[]getCameraIdList()
Return the list of currently connected camera devices by identifier.

Non-removable cameras use integers starting at 0 for their identifiers, while removable cameras have a unique identifier for each individual device, even if they are the same model.

return
The list of currently connected camera devices.

        synchronized (mLock) {
            // ID list creation handles various known failures in device enumeration, so only
            // exceptions it'll throw are unexpected, and should be propagated upward.
            return getOrCreateDeviceIdListLocked().toArray(new String[0]);
        }
    
private java.util.ArrayListgetOrCreateDeviceIdListLocked()
Return or create the list of currently connected camera devices.

In case of errors connecting to the camera service, will return an empty list.

        if (mDeviceIdList == null) {
            int numCameras = 0;
            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
            ArrayList<String> deviceIdList = new ArrayList<>();

            // If no camera service, then no devices
            if (cameraService == null) {
                return deviceIdList;
            }

            try {
                numCameras = cameraService.getNumberOfCameras();
            } catch(CameraRuntimeException e) {
                throw e.asChecked();
            } catch (RemoteException e) {
                // camera service just died - if no camera service, then no devices
                return deviceIdList;
            }

            CameraMetadataNative info = new CameraMetadataNative();
            for (int i = 0; i < numCameras; ++i) {
                // Non-removable cameras use integers starting at 0 for their
                // identifiers
                boolean isDeviceSupported = false;
                try {
                    cameraService.getCameraCharacteristics(i, info);
                    if (!info.isEmpty()) {
                        isDeviceSupported = true;
                    } else {
                        throw new AssertionError("Expected to get non-empty characteristics");
                    }
                } catch(IllegalArgumentException  e) {
                    // Got a BAD_VALUE from service, meaning that this
                    // device is not supported.
                } catch(CameraRuntimeException e) {
                    // DISCONNECTED means that the HAL reported an low-level error getting the
                    // device info; skip listing the device.  Other errors,
                    // propagate exception onward
                    if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
                        throw e.asChecked();
                    }
                } catch(RemoteException e) {
                    // Camera service died - no devices to list
                    deviceIdList.clear();
                    return deviceIdList;
                }

                if (isDeviceSupported) {
                    deviceIdList.add(String.valueOf(i));
                } else {
                    Log.w(TAG, "Error querying camera device " + i + " for listing.");
                }

            }
            mDeviceIdList = deviceIdList;
        }
        return mDeviceIdList;
    
public voidopenCamera(java.lang.String cameraId, CameraDevice.StateCallback callback, android.os.Handler handler)
Open a connection to a camera with the given ID.

Use {@link #getCameraIdList} to get the list of available camera devices. Note that even if an id is listed, open may fail if the device is disconnected between the calls to {@link #getCameraIdList} and {@link #openCamera}.

Once the camera is successfully opened, {@link CameraDevice.StateCallback#onOpened} will be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up for operation by calling {@link CameraDevice#createCaptureSession} and {@link CameraDevice#createCaptureRequest}

If the camera becomes disconnected during initialization after this function call returns, {@link CameraDevice.StateCallback#onDisconnected} with a {@link CameraDevice} in the disconnected state (and {@link CameraDevice.StateCallback#onOpened} will be skipped).

If opening the camera device fails, then the device callback's {@link CameraDevice.StateCallback#onError onError} method will be called, and subsequent calls on the camera device will throw a {@link CameraAccessException}.

param
cameraId The unique identifier of the camera device to open
param
callback The callback which is invoked once the camera is opened
param
handler The handler on which the callback should be invoked, or {@code null} to use the current thread's {@link android.os.Looper looper}.
throws
CameraAccessException if the camera is disabled by device policy, or the camera has become or was disconnected.
throws
IllegalArgumentException if cameraId or the callback was null, or the cameraId does not match any currently or previously available camera device.
throws
SecurityException if the application does not have permission to access the camera
see
#getCameraIdList
see
android.app.admin.DevicePolicyManager#setCameraDisabled


        if (cameraId == null) {
            throw new IllegalArgumentException("cameraId was null");
        } else if (callback == null) {
            throw new IllegalArgumentException("callback was null");
        } else if (handler == null) {
            if (Looper.myLooper() != null) {
                handler = new Handler();
            } else {
                throw new IllegalArgumentException(
                        "Looper doesn't exist in the calling thread");
            }
        }

        openCameraDeviceUserAsync(cameraId, callback, handler);
    
private CameraDeviceopenCameraDeviceUserAsync(java.lang.String cameraId, CameraDevice.StateCallback callback, android.os.Handler handler)
Helper for openning a connection to a camera with the given ID.

param
cameraId The unique identifier of the camera device to open
param
callback The callback for the camera. Must not be null.
param
handler The handler to invoke the callback on. Must not be null.
throws
CameraAccessException if the camera is disabled by device policy, or too many camera devices are already open, or the cameraId does not match any currently available camera device.
throws
SecurityException if the application does not have permission to access the camera
throws
IllegalArgumentException if callback or handler is null.
return
A handle to the newly-created camera device.
see
#getCameraIdList
see
android.app.admin.DevicePolicyManager#setCameraDisabled

        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
        CameraDevice device = null;
        try {

            synchronized (mLock) {

                ICameraDeviceUser cameraUser = null;

                android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
                        new android.hardware.camera2.impl.CameraDeviceImpl(
                                cameraId,
                                callback,
                                handler,
                                characteristics);

                BinderHolder holder = new BinderHolder();

                ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
                int id = Integer.parseInt(cameraId);
                try {
                    if (supportsCamera2ApiLocked(cameraId)) {
                        // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
                        ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
                        if (cameraService == null) {
                            throw new CameraRuntimeException(
                                CameraAccessException.CAMERA_DISCONNECTED,
                                "Camera service is currently unavailable");
                        }
                        cameraService.connectDevice(callbacks, id,
                                mContext.getPackageName(), USE_CALLING_UID, holder);
                        cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
                    } else {
                        // Use legacy camera implementation for HAL1 devices
                        Log.i(TAG, "Using legacy camera HAL.");
                        cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
                    }
                } catch (CameraRuntimeException e) {
                    if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
                        throw new AssertionError("Should've gone down the shim path");
                    } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
                            e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
                            e.getReason() == CameraAccessException.CAMERA_DISABLED ||
                            e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
                            e.getReason() == CameraAccessException.CAMERA_ERROR) {
                        // Received one of the known connection errors
                        // The remote camera device cannot be connected to, so
                        // set the local camera to the startup error state
                        deviceImpl.setRemoteFailure(e);

                        if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
                                e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) {
                            // Per API docs, these failures call onError and throw
                            throw e.asChecked();
                        }
                    } else {
                        // Unexpected failure - rethrow
                        throw e;
                    }
                } catch (RemoteException e) {
                    // Camera service died - act as if it's a CAMERA_DISCONNECTED case
                    CameraRuntimeException ce = new CameraRuntimeException(
                        CameraAccessException.CAMERA_DISCONNECTED,
                        "Camera service is currently unavailable", e);
                    deviceImpl.setRemoteFailure(ce);
                    throw ce.asChecked();
                }

                // TODO: factor out callback to be non-nested, then move setter to constructor
                // For now, calling setRemoteDevice will fire initial
                // onOpened/onUnconfigured callbacks.
                deviceImpl.setRemoteDevice(cameraUser);
                device = deviceImpl;
            }

        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
                    + cameraId);
        } catch (CameraRuntimeException e) {
            throw e.asChecked();
        }
        return device;
    
public voidregisterAvailabilityCallback(android.hardware.camera2.CameraManager$AvailabilityCallback callback, android.os.Handler handler)
Register a callback to be notified about camera device availability.

Registering the same callback again will replace the handler with the new one provided.

The first time a callback is registered, it is immediately called with the availability status of all currently known camera devices.

Since this callback will be registered with the camera service, remember to unregister it once it is no longer needed; otherwise the callback will continue to receive events indefinitely and it may prevent other resources from being released. Specifically, the callbacks will be invoked independently of the general activity lifecycle and independently of the state of individual CameraManager instances.

param
callback the new callback to send camera availability notices to
param
handler The handler on which the callback should be invoked, or {@code null} to use the current thread's {@link android.os.Looper looper}.

        if (handler == null) {
            Looper looper = Looper.myLooper();
            if (looper == null) {
                throw new IllegalArgumentException(
                        "No handler given, and current thread has no looper!");
            }
            handler = new Handler(looper);
        }

        CameraManagerGlobal.get().registerAvailabilityCallback(callback, handler);
    
private booleansupportsCamera2ApiLocked(java.lang.String cameraId)
Queries the camera service if it supports the camera2 api directly, or needs a shim.

param
cameraId a non-{@code null} camera identifier
return
{@code false} if the legacy shim needs to be used, {@code true} otherwise.

        return supportsCameraApiLocked(cameraId, API_VERSION_2);
    
private booleansupportsCameraApiLocked(java.lang.String cameraId, int apiVersion)
Queries the camera service if it supports a camera api directly, or needs a shim.

param
cameraId a non-{@code null} camera identifier
param
apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2}
return
{@code true} if connecting will work for that device version.

        int id = Integer.parseInt(cameraId);

        /*
         * Possible return values:
         * - NO_ERROR => CameraX API is supported
         * - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception)
         * - Remote exception => If the camera service died
         *
         * Anything else is an unexpected error we don't want to recover from.
         */
        try {
            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
            // If no camera service, no support
            if (cameraService == null) return false;

            int res = cameraService.supportsCameraApi(id, apiVersion);

            if (res != CameraServiceBinderDecorator.NO_ERROR) {
                throw new AssertionError("Unexpected value " + res);
            }
            return true;
        } catch (CameraRuntimeException e) {
            if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) {
                throw e;
            }
            // API level is not supported
        } catch (RemoteException e) {
            // Camera service is now down, no support for any API level
        }
        return false;
    
public voidunregisterAvailabilityCallback(android.hardware.camera2.CameraManager$AvailabilityCallback callback)
Remove a previously-added callback; the callback will no longer receive connection and disconnection callbacks.

Removing a callback that isn't registered has no effect.

param
callback The callback to remove from the notification list

        CameraManagerGlobal.get().unregisterAvailabilityCallback(callback);