diff options
| -rw-r--r-- | api/current.txt | 54 | ||||
| -rw-r--r-- | core/java/android/hardware/camera2/CameraCaptureSession.java | 588 | ||||
| -rw-r--r-- | core/java/android/hardware/camera2/CameraDevice.java | 149 | ||||
| -rw-r--r-- | core/java/android/hardware/camera2/CameraManager.java | 38 | ||||
| -rw-r--r-- | core/java/android/hardware/camera2/impl/CameraDevice.java | 8 |
5 files changed, 797 insertions, 40 deletions
diff --git a/api/current.txt b/api/current.txt index c38a82fc0698..a021d59663c0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -12134,6 +12134,35 @@ package android.hardware.camera2 { field public static final int CAMERA_ERROR = 3; // 0x3 } + public abstract class CameraCaptureSession implements java.lang.AutoCloseable { + ctor public CameraCaptureSession(); + method public abstract void abortCaptures() throws android.hardware.camera2.CameraAccessException; + method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract void close(); + method public abstract android.hardware.camera2.CameraDevice getDevice(); + method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException; + } + + public static abstract class CameraCaptureSession.CaptureListener { + ctor public CameraCaptureSession.CaptureListener(); + method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult); + method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure); + method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraDevice, int, int); + method public void onCaptureStarted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, long); + } + + public static abstract class CameraCaptureSession.StateListener { + ctor public CameraCaptureSession.StateListener(); + method public void onActive(android.hardware.camera2.CameraCaptureSession); + method public void onClosed(android.hardware.camera2.CameraCaptureSession); + method public abstract void onConfigureFailed(android.hardware.camera2.CameraCaptureSession); + method public abstract void onConfigured(android.hardware.camera2.CameraCaptureSession); + method public void onReady(android.hardware.camera2.CameraCaptureSession); + } + public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata { method public T get(android.hardware.camera2.CameraMetadata.Key<T>); method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureRequestKeys(); @@ -12201,16 +12230,17 @@ package android.hardware.camera2 { } public abstract interface CameraDevice implements java.lang.AutoCloseable { - method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; method public abstract void close(); - method public abstract void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException; method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException; - method public abstract void flush() throws android.hardware.camera2.CameraAccessException; + method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated void flush() throws android.hardware.camera2.CameraAccessException; method public abstract java.lang.String getId(); - method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method public abstract deprecated void stopRepeating() throws android.hardware.camera2.CameraAccessException; field public static final int TEMPLATE_MANUAL = 6; // 0x6 field public static final int TEMPLATE_PREVIEW = 1; // 0x1 field public static final int TEMPLATE_RECORD = 3; // 0x3 @@ -12219,7 +12249,7 @@ package android.hardware.camera2 { field public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5; // 0x5 } - public static abstract class CameraDevice.CaptureListener { + public static abstract deprecated class CameraDevice.CaptureListener { ctor public CameraDevice.CaptureListener(); method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult); method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure); @@ -12229,14 +12259,14 @@ package android.hardware.camera2 { public static abstract class CameraDevice.StateListener { ctor public CameraDevice.StateListener(); - method public void onActive(android.hardware.camera2.CameraDevice); - method public void onBusy(android.hardware.camera2.CameraDevice); + method public deprecated void onActive(android.hardware.camera2.CameraDevice); + method public deprecated void onBusy(android.hardware.camera2.CameraDevice); method public void onClosed(android.hardware.camera2.CameraDevice); method public abstract void onDisconnected(android.hardware.camera2.CameraDevice); method public abstract void onError(android.hardware.camera2.CameraDevice, int); - method public void onIdle(android.hardware.camera2.CameraDevice); + method public deprecated void onIdle(android.hardware.camera2.CameraDevice); method public abstract void onOpened(android.hardware.camera2.CameraDevice); - method public void onUnconfigured(android.hardware.camera2.CameraDevice); + method public deprecated void onUnconfigured(android.hardware.camera2.CameraDevice); field public static final int ERROR_CAMERA_DEVICE = 4; // 0x4 field public static final int ERROR_CAMERA_DISABLED = 3; // 0x3 field public static final int ERROR_CAMERA_IN_USE = 1; // 0x1 diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java new file mode 100644 index 000000000000..8391209687fa --- /dev/null +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -0,0 +1,588 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2; + +import android.os.Handler; +import java.util.List; + +/** + * A configured capture session for a {@link CameraDevice}, used for capturing + * images from the camera. + * + * <p>A CameraCaptureSession is created by providing a set of target output surfaces to + * {@link CameraDevice#createCaptureSession createCaptureSession}. Once created, the session is + * active until a new session is created by the camera device, or the camera device is closed.</p> + * + * <p>Creating a session is an expensive operation and can take several hundred milliseconds, since + * it requires configuring the camera device's internal pipelines and allocating memory buffers for + * sending images to the desired targets. While + * {@link CameraDevice#createCaptureSession createCaptureSession} will provide a + * CameraCaptureSession object immediately, configuration won't be complete until the + * {@link CameraCaptureSession.StateListener#onConfigured onConfigured} callback is called for the + * first time. If configuration cannot be completed, then the + * {@link CameraCaptureSession.StateListener#onConfigureFailed onConfigureFailed} is called, and the + * session will not become active.</p> + * + * <p>Any capture requests (repeating or non-repeating) submitted before the session is ready will + * be queued up and will begin capture once the session becomes ready. In case the session cannot be + * configured and {@link StateListener#onConfigureFailed onConfigureFailed} is called, all queued + * capture requests are discarded.</p> + * + * <p>If a new session is created by the camera device, then the previous session is closed, and its + * associated {@link StateListener#onClosed onClosed} callback will be invoked. All + * of the session methods will throw an IllegalStateException if called once the session is + * closed.</p> + * + * <p>A closed session clears any repeating requests (as if {@link #stopRepeating} had been called), + * but will still complete all of its in-progress capture requests as normal, before a newly + * created session takes over and reconfigures the camera device.</p> + */ +public abstract class CameraCaptureSession implements AutoCloseable { + + /** + * Get the camera device that this session is created for + */ + public abstract CameraDevice getDevice(); + + /** + * <p>Submit a request for an image to be captured by the camera device.</p> + * + * <p>The request defines all the parameters for capturing the single image, + * including sensor, lens, flash, and post-processing settings.</p> + * + * <p>Each request will produce one {@link CaptureResult} and produce new frames for one or more + * target Surfaces, set with the CaptureRequest builder's + * {@link CaptureRequest.Builder#addTarget} method. The target surfaces (set with + * {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when this + * capture session was created.</p> + * + * <p>Multiple requests can be in progress at once. They are processed in + * first-in, first-out order, with minimal delays between each + * capture. Requests submitted through this method have higher priority than + * those submitted through {@link #setRepeatingRequest} or + * {@link #setRepeatingBurst}, and will be processed as soon as the current + * repeat/repeatBurst processing completes.</p> + * + * @param request the settings for this capture + * @param listener The callback object to notify once this request has been + * processed. If null, no metadata will be produced for this capture, + * although image data will still be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException if the request targets Surfaces that are not configured as + * outputs for this session. Or if the handler is null, the + * listener is not null, and the calling thread has no looper. + * + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public abstract int capture(CaptureRequest request, CaptureListener listener, Handler handler) + throws CameraAccessException; + + /** + * Submit a list of requests to be captured in sequence as a burst. The + * burst will be captured in the minimum amount of time possible, and will + * not be interleaved with requests submitted by other capture or repeat + * calls. + * + * <p>The requests will be captured in order, each capture producing one {@link CaptureResult} + * and image buffers for one or more target {@link android.view.Surface surfaces}. The target + * surfaces (set with {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces + * provided when this capture session was created.</p> + * + * <p>The main difference between this method and simply calling + * {@link #capture} repeatedly is that this method guarantees that no + * other requests will be interspersed with the burst.</p> + * + * @param requests the list of settings for this burst capture + * @param listener The callback object to notify each time one of the + * requests in the burst has been processed. If null, no metadata will be + * produced for any requests in this burst, although image data will still + * be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException If the requests target Surfaces not currently configured as + * outputs. Or if the handler is null, the listener is not + * null, and the calling thread has no looper. + * + * @see #capture + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public abstract int captureBurst(List<CaptureRequest> requests, CaptureListener listener, + Handler handler) throws CameraAccessException; + + /** + * Request endlessly repeating capture of images by this capture session. + * + * <p>With this method, the camera device will continually capture images + * using the settings in the provided {@link CaptureRequest}, at the maximum + * rate possible.</p> + * + * <p>Repeating requests are a simple way for an application to maintain a + * preview or other continuous stream of frames, without having to + * continually submit identical requests through {@link #capture}.</p> + * + * <p>Repeat requests have lower priority than those submitted + * through {@link #capture} or {@link #captureBurst}, so if + * {@link #capture} is called when a repeating request is active, the + * capture request will be processed before any further repeating + * requests are processed.<p> + * + * <p>Repeating requests are a simple way for an application to maintain a + * preview or other continuous stream of frames, without having to submit + * requests through {@link #capture} at video rates.</p> + * + * <p>To stop the repeating capture, call {@link #stopRepeating}. Calling + * {@link #abortCaptures} will also clear the request.</p> + * + * <p>Calling this method will replace any earlier repeating request or + * burst set up by this method or {@link #setRepeatingBurst}, although any + * in-progress burst will be completed before the new repeat request will be + * used.</p> + * + * @param request the request to repeat indefinitely + * @param listener The callback object to notify every time the + * request finishes processing. If null, no metadata will be + * produced for this stream of requests, although image data will + * still be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException If the requests reference Surfaces that are not currently + * configured as outputs. Or if the handler is null, the + * listener is not null, and the calling thread has no looper. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingBurst + * @see #stopRepeating + * @see #abortCaptures + */ + public abstract int setRepeatingRequest(CaptureRequest request, CaptureListener listener, + Handler handler) throws CameraAccessException; + + /** + * <p>Request endlessly repeating capture of a sequence of images by this + * capture session.</p> + * + * <p>With this method, the camera device will continually capture images, + * cycling through the settings in the provided list of + * {@link CaptureRequest CaptureRequests}, at the maximum rate possible.</p> + * + * <p>If a request is submitted through {@link #capture} or + * {@link #captureBurst}, the current repetition of the request list will be + * completed before the higher-priority request is handled. This guarantees + * that the application always receives a complete repeat burst captured in + * minimal time, instead of bursts interleaved with higher-priority + * captures, or incomplete captures.</p> + * + * <p>Repeating burst requests are a simple way for an application to + * maintain a preview or other continuous stream of frames where each + * request is different in a predicatable way, without having to continually + * submit requests through {@link #captureBurst}.</p> + * + * <p>To stop the repeating capture, call {@link #stopRepeating}. Any + * ongoing burst will still be completed, however. Calling + * {@link #abortCaptures} will also clear the request.</p> + * + * <p>Calling this method will replace a previously-set repeating request or + * burst set up by this method or {@link #setRepeatingRequest}, although any + * in-progress burst will be completed before the new repeat burst will be + * used.</p> + * + * @param requests the list of requests to cycle through indefinitely + * @param listener The callback object to notify each time one of the + * requests in the repeating bursts has finished processing. If null, no + * metadata will be produced for this stream of requests, although image + * data will still be produced. + * @param handler the handler on which the listener should be invoked, or + * {@code null} to use the current thread's {@link android.os.Looper + * looper}. + * + * @return int A unique capture sequence ID used by + * {@link CaptureListener#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * @throws IllegalArgumentException If the requests reference Surfaces not currently configured + * as outputs. Or if the handler is null, the listener is not + * null, and the calling thread has no looper. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #stopRepeating + * @see #abortCaptures + */ + public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener, + Handler handler) throws CameraAccessException; + + /** + * <p>Cancel any ongoing repeating capture set by either + * {@link #setRepeatingRequest setRepeatingRequest} or + * {@link #setRepeatingBurst}. Has no effect on requests submitted through + * {@link #capture capture} or {@link #captureBurst captureBurst}.</p> + * + * <p>Any currently in-flight captures will still complete, as will any burst that is + * mid-capture. To ensure that the device has finished processing all of its capture requests + * and is in ready state, wait for the {@link StateListener#onReady} callback after + * calling this method.</p> + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * + * @see #setRepeatingRequest + * @see #setRepeatingBurst + * @see StateListener#onIdle + */ + public abstract void stopRepeating() throws CameraAccessException; + + /** + * Discard all captures currently pending and in-progress as fast as possible. + * + * <p>The camera device will discard all of its current work as fast as possible. Some in-flight + * captures may complete successfully and call {@link CaptureListener#onCaptureCompleted}, while + * others will trigger their {@link CaptureListener#onCaptureFailed} callbacks. If a repeating + * request or a repeating burst is set, it will be cleared.</p> + * + * <p>This method is the fastest way to switch the camera device to a new session with + * {@link CameraDevice#createCaptureSession}, at the cost of discarding in-progress work. It + * must be called before the new session is created. Once all pending requests are either + * completed or thrown away, the {@link StateListener#onReady} callback will be called, + * if the session has not been closed. Otherwise, the {@link StateListener#onClosed} + * callback will be fired when a new session is created by the camera device.</p> + * + * <p>Cancelling will introduce at least a brief pause in the stream of data from the camera + * device, since once the camera device is emptied, the first new request has to make it through + * the entire camera pipeline before new output buffers are produced.</p> + * + * <p>This means that using {@code abortCaptures()} to simply remove pending requests is not + * recommended; it's best used for quickly switching output configurations, or for cancelling + * long in-progress requests (such as a multi-second capture).</p> + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because a new + * session has been created or the camera device has been closed. + * + * @see #setRepeatingRequest + * @see #setRepeatingBurst + * @see #configureOutputs + */ + public abstract void abortCaptures() throws CameraAccessException; + + /** + * Close this capture session asynchronously. + * + * <p>Closing a session frees up the target output Surfaces of the session for reuse with either a + * new session, or to other APIs that can draw to Surfaces.</p> + * + * <p>Note that creating a new capture session with {@link CameraDevice#createCaptureSession} + * will close any existing capture session automatically, and call the older session listener's + * {@link StateListener#onClosed} callback. Using {@link CameraDevice#createCaptureSession} + * directly without closing is the recommended approach for quickly switching to a new session, + * since unchanged target outputs can be reused more efficiently.</p> + * + * <p>Once a session is closed, all methods on it will throw an IllegalStateException, and any + * repeating requests or bursts are stopped (as if {@link #stopRepeating()} was called). + * However, any in-progress capture requests submitted to the session will be completed as + * normal; once all captures have completed and the session has been torn down, + * {@link StateListener#onClosed} will be called.</p> + */ + @Override + public abstract void close(); + + /** + * A listener for tracking the state of a camera capture session. + * + */ + public static abstract class StateListener { + + /** + * This method is called when the camera device has finished configuring itself, and the + * session can start processing capture requests. + * + * <p>If there are capture requests already queued with the session, they will start + * processing once this callback is invoked, and the session will call {@link #onActive} + * right after this callback is invoked.</p> + * + * <p>If no capture requests have been submitted, then the session will invoke + * {@link #onReady} right after this callback.</p> + * + * <p>If the camera device configuration fails, then {@link #onConfigureFailed} will + * be invoked instead of this callback.</p> + * + */ + public abstract void onConfigured(CameraCaptureSession session); + + /** + * This method is called if the session cannot be configured as requested. + * + * <p>This can happen if the set of requested outputs contains unsupported sizes, + * or too many outputs are requested at once.</p> + * + * <p>The session is considered to be closed, and all methods called on it after this + * callback is invoked will throw an IllegalStateException. Any capture requests submitted + * to the session prior to this callback will be discarded and will not produce any + * callbacks on their listeners.</p> + */ + public abstract void onConfigureFailed(CameraCaptureSession session); + + /** + * This method is called every time the session has no more capture requests to process. + * + * <p>During the creation of a new session, this callback is invoked right after + * {@link #onConfigured} if no capture requests were submitted to the session prior to it + * completing configuration.</p> + * + * <p>Otherwise, this callback will be invoked any time the session finishes processing + * all of its active capture requests, and no repeating request or burst is set up.</p> + * + */ + public void onReady(CameraCaptureSession session) { + // default empty implementation + } + + /** + * This method is called when the session starts actively processing capture requests. + * + * <p>If capture requests are submitted prior to {@link #onConfigured} being called, + * then the session will start processing those requests immediately after the callback, + * and this method will be immediately called after {@link #onConfigured}. + * + * <p>If the session runs out of capture requests to process and calls {@link #onReady}, + * then this callback will be invoked again once new requests are submitted for capture.</p> + */ + public void onActive(CameraCaptureSession session) { + // default empty implementation + } + + /** + * This method is called when the session is closed. + * + * <p>A session is closed when a new session is created by the parent camera device, + * or when the parent camera device is closed (either by the user closing the device, + * or due to a camera device disconnection or fatal error).</p> + * + * <p>Once a session is closed, all methods on it will throw an IllegalStateException, and + * any repeating requests or bursts are stopped (as if {@link #stopRepeating()} was called). + * However, any in-progress capture requests submitted to the session will be completed + * as normal.</p> + */ + public void onClosed(CameraCaptureSession session) { + // default empty implementation + } + } + + /** + * <p>A listener for tracking the progress of a {@link CaptureRequest} + * submitted to the camera device.</p> + * + * <p>This listener is called when a request triggers a capture to start, + * and when the capture is complete. In case on an error capturing an image, + * the error method is triggered instead of the completion method.</p> + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public static abstract class CaptureListener { + + /** + * This constant is used to indicate that no images were captured for + * the request. + * + * @hide + */ + public static final int NO_FRAMES_CAPTURED = -1; + + /** + * This method is called when the camera device has started capturing + * the output image for the request, at the beginning of image exposure. + * + * <p>This callback is invoked right as the capture of a frame begins, + * so it is the most appropriate time for playing a shutter sound, + * or triggering UI indicators of capture.</p> + * + * <p>The request that is being used for this capture is provided, along + * with the actual timestamp for the start of exposure. This timestamp + * matches the timestamp that will be included in + * {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field}, + * and in the buffers sent to each output Surface. These buffer + * timestamps are accessible through, for example, + * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or + * {@link android.graphics.SurfaceTexture#getTimestamp()}.</p> + * + * <p>For the simplest way to play a shutter sound camera shutter or a + * video recording start/stop sound, see the + * {@link android.media.MediaActionSound} class.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera the CameraDevice sending the callback + * @param request the request for the capture that just begun + * @param timestamp the timestamp at start of capture, in nanoseconds. + * + * @see android.media.MediaActionSound + */ + public void onCaptureStarted(CameraDevice camera, + CaptureRequest request, long timestamp) { + // default empty implementation + } + + /** + * This method is called when some results from an image capture are + * available. + * + * <p>The result provided here will contain some subset of the fields of + * a full result. Multiple onCapturePartial calls may happen per + * capture; a given result field will only be present in one partial + * capture at most. The final onCaptureCompleted call will always + * contain all the fields, whether onCapturePartial was called or + * not.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera The CameraDevice sending the callback. + * @param request The request that was given to the CameraDevice + * @param result The partial output metadata from the capture, which + * includes a subset of the CaptureResult fields. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + * + * @hide + */ + public void onCapturePartial(CameraDevice camera, + CaptureRequest request, CaptureResult result) { + // default empty implementation + } + + /** + * This method is called when an image capture has completed and the + * result metadata is available. + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera The CameraDevice sending the callback. + * @param request The request that was given to the CameraDevice + * @param result The output metadata from the capture, including the + * final capture parameters and the state of the camera system during + * capture. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public void onCaptureCompleted(CameraDevice camera, + CaptureRequest request, CaptureResult result) { + // default empty implementation + } + + /** + * This method is called instead of {@link #onCaptureCompleted} when the + * camera device failed to produce a {@link CaptureResult} for the + * request. + * + * <p>Other requests are unaffected, and some or all image buffers from + * the capture may have been pushed to their respective output + * streams.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + * @param camera + * The CameraDevice sending the callback. + * @param request + * The request that was given to the CameraDevice + * @param failure + * The output failure from the capture, including the failure reason + * and the frame number. + * + * @see #capture + * @see #captureBurst + * @see #setRepeatingRequest + * @see #setRepeatingBurst + */ + public void onCaptureFailed(CameraDevice camera, + CaptureRequest request, CaptureFailure failure) { + // default empty implementation + } + + /** + * This method is called independently of the others in CaptureListener, + * when a capture sequence finishes and all {@link CaptureResult} + * or {@link CaptureFailure} for it have been returned via this listener. + * + * @param camera + * The CameraDevice sending the callback. + * @param sequenceId + * A sequence ID returned by the {@link #capture} family of functions. + * @param lastFrameNumber + * The last frame number (returned by {@link CaptureResult#getFrameNumber} + * or {@link CaptureFailure#getFrameNumber}) in the capture sequence. + * The last frame number may be equal to NO_FRAMES_CAPTURED if no images + * were captured for this sequence. This can happen, for example, when a + * repeating request or burst is cleared right after being set. + * + * @see CaptureResult#getFrameNumber() + * @see CaptureFailure#getFrameNumber() + * @see CaptureResult#getSequenceId() + * @see CaptureFailure#getSequenceId() + */ + public void onCaptureSequenceCompleted(CameraDevice camera, + int sequenceId, int lastFrameNumber) { + // default empty implementation + } + } + +} diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index ca03dae4fc91..77640d1d338d 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -242,10 +242,126 @@ public interface CameraDevice extends AutoCloseable { * @see StreamConfigurationMap#getOutputFormats() * @see StreamConfigurationMap#getOutputSizes(int) * @see StreamConfigurationMap#getOutputSizes(Class) + * @deprecated Use {@link #createCaptureSession} instead */ public void configureOutputs(List<Surface> outputs) throws CameraAccessException; /** + * <p>Create a new camera capture session by providing the target output set of Surfaces to the + * camera device.</p> + * + * <p>The active capture session determines the set of potential output Surfaces for + * the camera device for each capture request. A given request may use all + * or a only some of the outputs. Once the CameraCaptureSession is created, requests can be + * can be submitted with {@link CameraCaptureSession#capture capture}, + * {@link CameraCaptureSession#captureBurst captureBurst}, + * {@link CameraCaptureSession#setRepeatingRequest setRepeatingRequest}, or + * {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}.</p> + * + * <p>Surfaces suitable for inclusion as a camera output can be created for + * various use cases and targets:</p> + * + * <ul> + * + * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Set the size of the + * Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the sizes + * returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceView.class)} + * and then obtain the Surface by calling {@link android.view.SurfaceHolder#getSurface}.</li> + * + * <li>For accessing through an OpenGL texture via a + * {@link android.graphics.SurfaceTexture SurfaceTexture}: Set the size of + * the SurfaceTexture with + * {@link android.graphics.SurfaceTexture#setDefaultBufferSize} to be one + * of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceTexture.class)} + * before creating a Surface from the SurfaceTexture with + * {@link Surface#Surface}.</li> + * + * <li>For recording with {@link android.media.MediaCodec}: Call + * {@link android.media.MediaCodec#createInputSurface} after configuring + * the media codec to use one of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(MediaCodec.class)} + * </li> + * + * <li>For recording with {@link android.media.MediaRecorder}: Call + * {@link android.media.MediaRecorder#getSurface} after configuring the media recorder to use + * one of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(MediaRecorder.class)}, + * or configuring it to use one of the supported + * {@link android.media.CamcorderProfile CamcorderProfiles}.</li> + * + * <li>For efficient YUV processing with {@link android.renderscript}: + * Create a RenderScript + * {@link android.renderscript.Allocation Allocation} with a supported YUV + * type, the IO_INPUT flag, and one of the sizes returned by + * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(Allocation.class)}, + * Then obtain the Surface with + * {@link android.renderscript.Allocation#getSurface}.</li> + * + * <li>For access to raw, uncompressed or JPEG data in the application: Create a + * {@link android.media.ImageReader} object with the one of the supported + * {@link StreamConfigurationMap#getOutputFormats() output image formats}, and a + * size from the supported + * {@link StreamConfigurationMap#getOutputSizes(int) sizes for that format}. Then obtain + * a Surface from it with {@link android.media.ImageReader#getSurface}.</li> + * + * </ul> + * + * </p> + * + * <p>The camera device will query each Surface's size and formats upon this + * call, so they must be set to a valid setting at this time (in particular: + * if the format is user-visible, it must be one of + * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of + * {@link StreamConfigurationMap#getOutputSizes(int)}).</p> + * + * <p>It can take several hundred milliseconds for the session's configuration to complete, + * since camera hardware may need to be powered on or reconfigured. Once the configuration is + * complete and the session is ready to actually capture data, the provided + * {@link CameraCaptureSession.StateListener}'s + * {@link CameraCaptureSession.StateListener#onConfigured} callback will be called.</p> + * + * <p>If a prior CameraCaptureSession already exists when a new one is created, the previous + * session is closed. Any in-progress capture requests made on the prior session will be + * completed before the new session is configured and is able to start capturing its own + * requests. To minimize the transition time, the {@link CameraCaptureSession#abortCaptures} + * call can be used to discard the remaining requests for the prior capture session before a new + * one is created. Note that once the new session is created, the old one can no longer have its + * captures aborted.</p> + * + * <p>Using larger resolution outputs, or more outputs, can result in slower + * output rate from the device.</p> + * + * <p>Configuring a session with an empty or null list will close the current session, if + * any. This can be used to release the current session's target surfaces for another use.</p> + * + * @param outputs The new set of Surfaces that should be made available as + * targets for captured image data. + * @param listener The listener to notify about the status of the new capture session. + * @param handler The handler on which the listener should be invoked, or {@code null} to use + * the current thread's {@link android.os.Looper looper}. + * <!-- + * @return A new camera capture session to use, or null if an empty/null set of Surfaces is + * provided. + * --> + * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements, + * the listener is null, or the handler is null but the current + * thread has no looper. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see CameraCaptureSession + * @see StreamConfigurationMap#getOutputFormats() + * @see StreamConfigurationMap#getOutputSizes(int) + * @see StreamConfigurationMap#getOutputSizes(Class) + */ + public void createCaptureSession(List<Surface> outputs, + CameraCaptureSession.StateListener listener, Handler handler) + throws CameraAccessException; + + /** * <p>Create a {@link CaptureRequest.Builder} for new capture requests, * initialized with template for a target use case. The settings are chosen * to be the best options for the specific camera device, so it is not @@ -314,6 +430,7 @@ public interface CameraDevice extends AutoCloseable { * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst + * @deprecated Use {@link CameraCaptureSession} instead */ public int capture(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -358,6 +475,7 @@ public interface CameraDevice extends AutoCloseable { * @see #capture * @see #setRepeatingRequest * @see #setRepeatingBurst + * @deprecated Use {@link CameraCaptureSession} instead */ public int captureBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -416,6 +534,7 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingBurst * @see #stopRepeating * @see #flush + * @deprecated Use {@link CameraCaptureSession} instead */ public int setRepeatingRequest(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -474,6 +593,7 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingRequest * @see #stopRepeating * @see #flush + * @deprecated Use {@link CameraCaptureSession} instead */ public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException; @@ -498,6 +618,7 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingRequest * @see #setRepeatingBurst * @see StateListener#onIdle + * @deprecated Use {@link CameraCaptureSession} instead */ public void stopRepeating() throws CameraAccessException; @@ -534,25 +655,24 @@ public interface CameraDevice extends AutoCloseable { * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #configureOutputs + * @deprecated Use {@link CameraCaptureSession} instead */ public void flush() throws CameraAccessException; /** - * Close the connection to this camera device. + * Close the connection to this camera device as quickly as possible. * - * <p>After this call, all calls to - * the camera device interface will throw a {@link IllegalStateException}, - * except for calls to close(). Once the device has fully shut down, the - * {@link StateListener#onClosed} callback will be called, and the camera is - * free to be re-opened.</p> + * <p>Immediately after this call, all calls to the camera device or active session interface + * will throw a {@link IllegalStateException}, except for calls to close(). Once the device has + * fully shut down, the {@link StateListener#onClosed} callback will be called, and the camera + * is free to be re-opened.</p> * - * <p>After this call, besides the final {@link StateListener#onClosed} call, no calls to the - * device's {@link StateListener} will occur, and any remaining submitted capture requests will - * not fire their {@link CaptureListener} callbacks.</p> + * <p>Immediately after this call, besides the final {@link StateListener#onClosed} calls, no + * further callbacks from the device or the active session will occur, and any remaining + * submitted capture requests will be discarded, as if + * {@link CameraCaptureSession#abortCaptures} had been called, except that no success or failure + * callbacks will be invoked.</p> * - * <p>To shut down as fast as possible, call the {@link #flush} method and then {@link #close} - * once the flush completes. This will discard some capture requests, but results in faster - * shutdown.</p> */ @Override public void close(); @@ -569,6 +689,7 @@ public interface CameraDevice extends AutoCloseable { * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst + * @deprecated Use {@link CameraCaptureSession} instead */ public static abstract class CaptureListener { @@ -834,6 +955,7 @@ public interface CameraDevice extends AutoCloseable { * <p>The default implementation of this method does nothing.</p> * * @param camera the camera device has that become unconfigured + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onUnconfigured(CameraDevice camera) { // Default empty implementation @@ -863,6 +985,7 @@ public interface CameraDevice extends AutoCloseable { * @see CameraDevice#captureBurst * @see CameraDevice#setRepeatingBurst * @see CameraDevice#setRepeatingRequest + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onActive(CameraDevice camera) { // Default empty implementation @@ -896,6 +1019,7 @@ public interface CameraDevice extends AutoCloseable { * * @see CameraDevice#configureOutputs * @see CameraDevice#flush + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onBusy(CameraDevice camera) { // Default empty implementation @@ -943,6 +1067,7 @@ public interface CameraDevice extends AutoCloseable { * @see CameraDevice#configureOutputs * @see CameraDevice#stopRepeating * @see CameraDevice#flush + * @deprecated Use {@link CameraCaptureSession.StateListener} instead. */ public void onIdle(CameraDevice camera) { // Default empty implementation diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index cb463a61b444..03b342c03ff5 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -199,11 +199,7 @@ public final class CameraManager { } /** - * 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}. + * Helper for openning a connection to a camera with the given ID. * * @param cameraId The unique identifier of the camera device to open * @param listener The listener for the camera. Must not be null. @@ -216,20 +212,22 @@ public final class CameraManager { * @throws SecurityException if the application does not have permission to * access the camera * @throws IllegalArgumentException if listener or handler is null. + * @return A handle to the newly-created camera device. * * @see #getCameraIdList * @see android.app.admin.DevicePolicyManager#setCameraDisabled */ - private void openCameraDeviceUserAsync(String cameraId, + private CameraDevice openCameraDeviceUserAsync(String cameraId, CameraDevice.StateListener listener, Handler handler) throws CameraAccessException { + CameraDevice device = null; try { synchronized (mLock) { ICameraDeviceUser cameraUser; - android.hardware.camera2.impl.CameraDevice device = + android.hardware.camera2.impl.CameraDevice deviceImpl = new android.hardware.camera2.impl.CameraDevice( cameraId, listener, @@ -237,7 +235,7 @@ public final class CameraManager { BinderHolder holder = new BinderHolder(); - ICameraDeviceCallbacks callbacks = device.getCallbacks(); + ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); int id = Integer.parseInt(cameraId); try { mCameraService.connectDevice(callbacks, id, mContext.getPackageName(), @@ -257,7 +255,8 @@ public final class CameraManager { // TODO: factor out listener to be non-nested, then move setter to constructor // For now, calling setRemoteDevice will fire initial // onOpened/onUnconfigured callbacks. - device.setRemoteDevice(cameraUser); + deviceImpl.setRemoteDevice(cameraUser); + device = deviceImpl; } } catch (NumberFormatException e) { @@ -268,6 +267,7 @@ public final class CameraManager { } catch (RemoteException e) { // impossible } + return device; } /** @@ -278,20 +278,26 @@ public final class CameraManager { * is disconnected between the calls to {@link #getCameraIdList} and * {@link #openCamera}.</p> * - * <p>If the camera successfully opens after this function call returns, - * {@link CameraDevice.StateListener#onOpened} will be invoked with the - * newly opened {@link CameraDevice} in the unconfigured state.</p> + * <p>Once the camera is successfully opened, {@link CameraDevice.StateListener#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}</p> * + * <!-- + * <p>Since the camera device will be opened asynchronously, any asynchronous operations done + * on the returned CameraDevice instance will be queued up until the device startup has + * completed and the listener's {@link CameraDevice.StateListener#onOpened onOpened} method is + * called. The pending operations are then processed in order.</p> + * --> * <p>If the camera becomes disconnected during initialization * after this function call returns, * {@link CameraDevice.StateListener#onDisconnected} with a * {@link CameraDevice} in the disconnected state (and * {@link CameraDevice.StateListener#onOpened} will be skipped).</p> * - * <p>If the camera fails to initialize after this function call returns, - * {@link CameraDevice.StateListener#onError} will be invoked with a - * {@link CameraDevice} in the error state (and - * {@link CameraDevice.StateListener#onOpened} will be skipped).</p> + * <p>If opening the camera device fails, then the device listener's + * {@link CameraDevice.StateListener#onError onError} method will be called, and subsequent + * calls on the camera device will throw an {@link IllegalStateException}.</p> * * @param cameraId * The unique identifier of the camera device to open diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java index e78ffff297c5..b082a7076452 100644 --- a/core/java/android/hardware/camera2/impl/CameraDevice.java +++ b/core/java/android/hardware/camera2/impl/CameraDevice.java @@ -19,6 +19,7 @@ package android.hardware.camera2.impl; import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE; import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.ICameraDeviceCallbacks; @@ -253,6 +254,13 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override + public void createCaptureSession(List<Surface> outputs, + CameraCaptureSession.StateListener listener, Handler handler) + throws CameraAccessException { + // TODO + } + + @Override public CaptureRequest.Builder createCaptureRequest(int templateType) throws CameraAccessException { synchronized (mLock) { |