Merge "consumer ir: clarify @link in documentation" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index b5930ec..9252152 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10815,16 +10815,17 @@
}
public abstract interface CameraDevice implements java.lang.AutoCloseable {
- method public abstract void capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
- method public abstract void captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void 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() throws java.lang.Exception;
method public abstract void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException;
- method public abstract android.hardware.camera2.CaptureRequest createCaptureRequest(int) 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 java.lang.String getId();
method public abstract android.hardware.camera2.CameraProperties getProperties() throws android.hardware.camera2.CameraAccessException;
- method public abstract void setErrorListener(android.hardware.camera2.CameraDevice.ErrorListener);
- method public abstract void setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
- method public abstract void setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void setDeviceListener(android.hardware.camera2.CameraDevice.CameraDeviceListener, android.os.Handler);
+ method public abstract void setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void 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 void waitUntilIdle() throws android.hardware.camera2.CameraAccessException;
field public static final int TEMPLATE_MANUAL = 5; // 0x5
@@ -10834,39 +10835,38 @@
field public static final int TEMPLATE_VIDEO_SNAPSHOT = 4; // 0x4
}
- public static abstract interface CameraDevice.CaptureListener {
- method public abstract void onCaptureComplete(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
- method public abstract void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest);
+ public static abstract class CameraDevice.CameraDeviceListener {
+ ctor public CameraDevice.CameraDeviceListener();
+ method public void onCameraDisconnected(android.hardware.camera2.CameraDevice);
+ method public void onCameraError(android.hardware.camera2.CameraDevice, int);
+ method public void onCameraIdle(android.hardware.camera2.CameraDevice);
+ field public static final int ERROR_CAMERA_DEVICE = 1; // 0x1
+ field public static final int ERROR_CAMERA_SERVICE = 2; // 0x2
}
- public static abstract interface CameraDevice.ErrorListener {
- method public abstract void onCameraDeviceError(android.hardware.camera2.CameraDevice, int);
- field public static final int DEVICE_DISCONNECTED = 1; // 0x1
- field public static final int DEVICE_ERROR = 2; // 0x2
- field public static final int SERVICE_ERROR = 3; // 0x3
+ public static abstract 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);
+ method public void onCaptureStarted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, long);
}
public final class CameraManager {
+ method public void addAvailabilityListener(android.hardware.camera2.CameraManager.AvailabilityListener, android.os.Handler);
+ method public java.lang.String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
method public android.hardware.camera2.CameraProperties getCameraProperties(java.lang.String) throws android.hardware.camera2.CameraAccessException;
- method public java.lang.String[] getDeviceIdList() throws android.hardware.camera2.CameraAccessException;
method public android.hardware.camera2.CameraDevice openCamera(java.lang.String) throws android.hardware.camera2.CameraAccessException;
- method public void registerCameraListener(android.hardware.camera2.CameraManager.CameraListener);
- method public void unregisterCameraListener(android.hardware.camera2.CameraManager.CameraListener);
+ method public void removeAvailabilityListener(android.hardware.camera2.CameraManager.AvailabilityListener);
}
- public static abstract interface CameraManager.CameraListener {
- method public abstract void onCameraAvailable(java.lang.String);
- method public abstract void onCameraUnavailable(java.lang.String);
+ public static abstract class CameraManager.AvailabilityListener {
+ ctor public CameraManager.AvailabilityListener();
+ method public void onCameraAvailable(java.lang.String);
+ method public void onCameraUnavailable(java.lang.String);
}
- public class CameraMetadata implements java.lang.AutoCloseable android.os.Parcelable {
- ctor public CameraMetadata();
- method public void close() throws java.lang.Exception;
- method public int describeContents();
- method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
- method public void readFromParcel(android.os.Parcel);
- method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T);
- method public void writeToParcel(android.os.Parcel, int);
+ public abstract class CameraMetadata {
+ method public abstract T get(android.hardware.camera2.CameraMetadata.Key<T>);
field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
@@ -10950,7 +10950,6 @@
field public static final int CONTROL_SCENE_MODE_SUNSET = 10; // 0xa
field public static final int CONTROL_SCENE_MODE_THEATRE = 7; // 0x7
field public static final int CONTROL_SCENE_MODE_UNSUPPORTED = 0; // 0x0
- field public static final android.os.Parcelable.Creator CREATOR;
field public static final int EDGE_MODE_FAST = 1; // 0x1
field public static final int EDGE_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int EDGE_MODE_OFF = 0; // 0x0
@@ -10983,14 +10982,13 @@
}
public static class CameraMetadata.Key {
- ctor public CameraMetadata.Key(java.lang.String, java.lang.Class<T>);
method public final boolean equals(java.lang.Object);
method public final java.lang.String getName();
method public final int hashCode();
}
public final class CameraProperties extends android.hardware.camera2.CameraMetadata {
- ctor public CameraProperties();
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_RANGE;
@@ -11033,10 +11031,10 @@
}
public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
- method public void addTarget(android.view.Surface);
+ method public int describeContents();
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
method public java.lang.Object getTag();
- method public void removeTarget(android.view.Surface);
- method public void setTag(java.lang.Object);
+ method public void writeToParcel(android.os.Parcel, int);
field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
@@ -11086,7 +11084,17 @@
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
}
+ public static final class CaptureRequest.Builder {
+ method public void addTarget(android.view.Surface);
+ method public android.hardware.camera2.CaptureRequest build();
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public void removeTarget(android.view.Surface);
+ method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T);
+ method public void setTag(java.lang.Object);
+ }
+
public final class CaptureResult extends android.hardware.camera2.CameraMetadata {
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
@@ -12745,7 +12753,9 @@
field public static final java.lang.String KEY_IS_ADTS = "is-adts";
field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
field public static final java.lang.String KEY_LANGUAGE = "language";
+ field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
+ field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
field public static final java.lang.String KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index a4a56d7..75c0f7d 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -17,6 +17,8 @@
package android.hardware.camera2;
import android.view.Surface;
+import android.os.Handler;
+import android.util.Log;
import java.lang.AutoCloseable;
import java.util.List;
@@ -99,6 +101,26 @@
public static final int TEMPLATE_MANUAL = 5;
/**
+ * Get the ID of this camera device.
+ *
+ * <p>This matches the ID given to {@link CameraManager#openCamera} to instantiate this
+ * this camera device.</p>
+ *
+ * <p>This ID can be used to query the camera device's {@link
+ * CameraProperties fixed properties} with {@link
+ * CameraManager#getCameraProperties}.</p>
+ *
+ * <p>This method can be called even if the device has been closed or has encountered
+ * a serious error.</p>
+ *
+ * @return the ID for this camera device
+ *
+ * @see CameraManager#getCameraProperties
+ * @see CameraManager#getDeviceIdList
+ */
+ public String getId();
+
+ /**
* Get the static properties for this camera. These are identical to the
* properties returned by {@link CameraManager#getCameraProperties}.
*
@@ -109,6 +131,7 @@
* @see CameraManager#getCameraProperties
*/
public CameraProperties getProperties() throws CameraAccessException;
+
/**
* <p>Set up a new output set of Surfaces for the camera device.</p>
*
@@ -177,10 +200,16 @@
* if the format is user-visible, it must be one of android.scaler.availableFormats;
* and the size must be one of android.scaler.available[Processed|Jpeg]Sizes).</p>
*
- * <p>To change the configuration after requests have been submitted to the
- * device, the camera device must be idle. To idle the device, stop any
- * repeating requests with {@link #stopRepeating stopRepeating}, and then
- * call {@link #waitUntilIdle waitUntilIdle}.</p>
+ * <p>To change the output, the camera device must be idle. The device is considered
+ * to be idle once all in-flight and pending capture requests have been processed,
+ * and all output image buffers from the captures have been sent to their destination
+ * Surfaces.</p>
+ *
+ * <p>To reach an idle state without cancelling any submitted captures, first
+ * stop any repeating request/burst with {@link #stopRepeating}, and then
+ * wait for the {@link CameraDeviceListener#onCameraIdle} callback to be
+ * called. To idle as fast as possible, use {@link #flush} and wait for the
+ * idle callback.</p>
*
* <p>Using larger resolution outputs, or more outputs, can result in slower
* output rate from the device.</p>
@@ -193,19 +222,25 @@
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device is not idle, or has
* encountered a fatal error
+ *
+ * @see CameraDeviceListener#onCameraIdle
+ * @see #stopRepeating
+ * @see #flush
*/
public void configureOutputs(List<Surface> outputs) throws CameraAccessException;
/**
- * <p>Create a {@link CaptureRequest} 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 recommended to reuse the same request for a
- * different camera device; create a request for that device and override
- * the settings as desired, instead.</p>
+ * <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
+ * recommended to reuse the same request for a different camera device;
+ * create a builder specific for that device and template and override the
+ * settings as desired, instead.</p>
*
* @param templateType An enumeration selecting the use case for this
* request; one of the CameraDevice.TEMPLATE_ values.
- * @return a filled-in CaptureRequest, except for output streams
+ * @return a builder for a capture request, initialized with default
+ * settings for that template, and no output streams
*
* @throws IllegalArgumentException if the templateType is not in the list
* of supported templates.
@@ -219,7 +254,7 @@
* @see #TEMPLATE_VIDEO_SNAPSHOT
* @see #TEMPLATE_MANUAL
*/
- public CaptureRequest createCaptureRequest(int templateType)
+ public CaptureRequest.Builder createCaptureRequest(int templateType)
throws CameraAccessException;
/**
@@ -229,7 +264,10 @@
* 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, as defined by the request's .</p>
+ * frames for one or more target Surfaces, set with the CaptureRequest
+ * builder's {@link CaptureRequest.Builder#addTarget} method. The target
+ * surfaces must be configured as active outputs with
+ * {@link #configureOutputs} before calling this method.</p>
*
* <p>Multiple requests can be in progress at once. They are processed in
* first-in, first-out order, with minimal delays between each
@@ -242,27 +280,36 @@
* @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}.
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @throws IllegalArgumentException If the request targets 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 #captureBurst
* @see #setRepeatingRequest
* @see #setRepeatingBurst
*/
- public void capture(CaptureRequest request, CaptureListener listener)
+ public void capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException;
/**
- * <p>Submit a list of requests to be captured in sequence as a burst. The
+ * 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>
+ * calls.
*
* <p>The requests will be captured in order, each capture producing one
- * {@link CaptureResult} and frames for one or more
- * target {@link android.view.Surface surfaces}.</p>
+ * {@link CaptureResult} and image buffers for one or more target
+ * {@link android.view.Surface surfaces}. The target surfaces for each
+ * request (set with {@link CaptureRequest.Builder#addTarget}) must be
+ * configured as active outputs with {@link #configureOutputs} before
+ * calling this method.</p>
*
* <p>The main difference between this method and simply calling
* {@link #capture} repeatedly is that this method guarantees that no
@@ -273,29 +320,38 @@
* 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}.
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @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 void captureBurst(List<CaptureRequest> requests,
- CaptureListener listener) throws CameraAccessException;
+ public void captureBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException;
/**
- * <p>Request endlessly repeating capture of images by this
- * CameraDevice.</p>
+ * Request endlessly repeating capture of images by this CameraDevice.
*
- * <p>With this method, the CameraDevice will continually capture
- * images using the settings in the provided {@link
- * CaptureRequest}, at the maximum rate possible.</p>
+ * <p>With this method, the CameraDevice 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
- * capture() is called when a repeating request is active, the
+ * {@link #capture} is called when a repeating request is active, the
* capture request will be processed before any further repeating
* requests are processed.<p>
*
@@ -306,20 +362,27 @@
* <p>To stop the repeating capture, call {@link #stopRepeating}. Calling
* {@link #flush} will also clear the request.</p>
*
- * <p>Calling repeat will replace a burst set up by {@link
- * #setRepeatingBurst}, although any in-progress burst will be
- * completed before the new repeat request will be used.</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}.
*
* @throws CameraAccessException if the camera device is no longer
* connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @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
@@ -327,8 +390,8 @@
* @see #stopRepeating
* @see #flush
*/
- public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
- throws CameraAccessException;
+ public void setRepeatingRequest(CaptureRequest request, CaptureListener listener,
+ Handler handler) throws CameraAccessException;
/**
* <p>Request endlessly repeating capture of a sequence of images by this
@@ -347,26 +410,33 @@
*
* <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 submit
- * requests through {@link #capture} at video rates.</p>
+ * 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 #flush} will also clear the request.</p>
*
- * <p>Calling repeatBurst will replace a repeating request set up by
- * {@link #setRepeatingRequest}, although any in-progress capture will be completed
- * before the new repeat burst will be used.</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}.
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @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
@@ -374,8 +444,8 @@
* @see #stopRepeating
* @see #flush
*/
- public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
- throws CameraAccessException;
+ public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException;
/**
* <p>Cancel any ongoing repeating capture set by either
@@ -385,8 +455,9 @@
*
* <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 idle state, use the
- * {@link #waitUntilIdle waitUntilIdle} method.</p>
+ * processing all of its capture requests and is in idle state, wait for the
+ * {@link CameraDeviceListener#onCameraIdle} callback after calling this
+ * method..</p>
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
@@ -394,7 +465,7 @@
*
* @see #setRepeatingRequest
* @see #setRepeatingBurst
- * @see #waitUntilIdle
+ * @see CameraDeviceListener#onCameraIdle
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed, the
@@ -429,16 +500,27 @@
public void waitUntilIdle() throws CameraAccessException;
/**
- * Set the error listener object to call when an asynchronous error
- * occurs. The errors reported here are only device-wide errors; errors
- * about individual requests or frames are reported through
- * {@link CaptureListener#onCaptureFailed}.
+ * Set the listener object to call when an asynchronous device event occurs,
+ * such as errors or idle notifications.
*
- * @param listener the ErrorListener to send asynchronous error
- * notifications to. Setting this to null will stop notifications about
- * asynchronous errors.
+ * <p>The events reported here are device-wide; notifications about
+ * individual capture requests or capture results are reported through
+ * {@link CaptureListener}.</p>
+ *
+ * <p>If the camera device is idle when the listener is set, then the
+ * {@link CameraDeviceListener#onCameraIdle} method will be immediately called,
+ * even if the device has never been active before.
+ * </p>
+ *
+ * @param listener the CameraDeviceListener to send device-level event
+ * notifications to. Setting this to null will stop notifications.
+ * @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}.
+ *
+ * @throws IllegalArgumentException if handler is null, the listener is
+ * not null, and the calling thread has no looper
*/
- public void setErrorListener(ErrorListener listener);
+ public void setDeviceListener(CameraDeviceListener listener, Handler handler);
/**
* Flush all captures currently pending and in-progress as fast as
@@ -446,7 +528,7 @@
*
* <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#onCaptureComplete}, while others will trigger
+ * {@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 by the flush.</p>
*
@@ -483,14 +565,60 @@
// TODO: We should decide on the behavior of in-flight requests should be on close.
/**
- * A listener for receiving metadata about completed image captures. The
- * metadata includes, among other things, the final capture settings and the
- * state of the control algorithms.
+ * <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 interface CaptureListener {
+ public static abstract class CaptureListener {
+
/**
- * <p>Called when a capture request has been processed by a
- * {@link CameraDevice}.</p>
+ * 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 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
@@ -503,14 +631,21 @@
* @see #setRepeatingRequest
* @see #setRepeatingBurst
*/
- public void onCaptureComplete(CameraDevice camera,
- CaptureRequest request, CaptureResult result);
+ public void onCaptureCompleted(CameraDevice camera,
+ CaptureRequest request, CaptureResult result) {
+ // default empty implementation
+ }
/**
- * <p>Called instead of onCaptureComplete when the camera device failed
- * to produce a CaptureResult for the request. Other requests are
- * unaffected, and some or all image buffers from the capture may have
- * been pushed to their respective output streams.</p>
+ * 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
@@ -521,62 +656,129 @@
* @see #setRepeatingBurst
*/
public void onCaptureFailed(CameraDevice camera,
- CaptureRequest request);
+ CaptureRequest request) {
+ // default empty implementation
+ }
}
/**
- * <p>A listener for asynchronous errors from the camera device. Errors
- * about specific {@link CaptureRequest CaptureRequests} are sent through
- * the capture {@link CaptureListener#onCaptureFailed listener}
- * interface. Errors reported through this listener affect the device as a
- * whole.</p>
+ * A listener for notifications about the state of a camera
+ * device.
+ *
+ * <p>These events include notifications about the device becoming idle (
+ * allowing for {@link #configureOutputs} to be called), about device
+ * disconnection, and about unexpected device errors.</p>
+ *
+ * <p>Events about the progress of specific {@link CaptureRequest
+ * CaptureRequests} are provided through a {@link CaptureListener} given to
+ * the {@link #capture}, {@link #captureBurst}, {@link
+ * #setRepeatingRequest}, or {@link #setRepeatingBurst} methods.
+ *
+ * @see #setDeviceListener
*/
- public interface ErrorListener {
+ public static abstract class CameraDeviceListener {
+
/**
- * <p>This camera device has been disconnected by the camera
- * service. Any attempt to call methods on this CameraDevice will throw
- * a {@link CameraAccessException}. The disconnection could be due to a
+ * An error code that can be reported by {@link #onCameraError}
+ * indicating that the camera device has encountered a fatal error.
+ *
+ * <p>The camera device needs to be re-opened to be used again.</p>
+ *
+ * @see #onCameraDeviceError
+ */
+ public static final int ERROR_CAMERA_DEVICE = 1;
+
+ /**
+ * An error code that can be reported by {@link #onCameraError}
+ * indicating that the camera service has encountered a fatal error.
+ *
+ * <p>The Android device may need to be shut down and restarted to restore
+ * camera function, or there may be a persistent hardware problem.</p>
+ *
+ * @see #onCameraDeviceError
+ */
+ public static final int ERROR_CAMERA_SERVICE = 2;
+
+ /**
+ * The method called when a camera device has finished processing all
+ * submitted capture requests and has reached an idle state.
+ *
+ * <p>An idle camera device can have its outputs changed by calling
+ * {@link CameraDevice#configureOutputs}.</p>
+ *
+ * <p>To idle and reconfigure outputs without cancelling any submitted
+ * capture requests, the application needs to clear its repeating
+ * request/burst, if set, with {@link CameraDevice#stopRepeating}, and
+ * then wait for this callback to be called before calling {@link
+ * CameraDevice#configureOutputs}.</p>
+ *
+ * <p>To idle and reconfigure a camera device as fast as possible, the
+ * {@link CameraDevice#flush} method can be used, which will discard all
+ * pending and in-progess capture requests. Once the {@link
+ * CameraDevice#flush} method is called, the application must wait for
+ * this callback to fire before calling {@link
+ * CameraDevice#configureOutputs}.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param camera the camera device that has become idle
+ *
+ * @see CameraDevice#configureOutputs
+ * @see CameraDevice#stopRepeating
+ * @see CameraDevice#flush
+ */
+ public void onCameraIdle(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device is no longer available for
+ * use.
+ *
+ * <p>Any attempt to call methods on this CameraDevice will throw a
+ * {@link CameraAccessException}. The disconnection could be due to a
* change in security policy or permissions; the physical disconnection
* of a removable camera device; or the camera being needed for a
* higher-priority use case.</p>
*
- * <p>There may still be capture completion or camera stream listeners
- * that will be called after this error is received.</p>
+ * <p>There may still be capture listener callbacks that are called
+ * after this method is called, or new image buffers that are delivered
+ * to active outputs.</p>
+ *
+ * <p>The default implementation logs a notice to the system log
+ * about the disconnection.</p>
+ *
+ * @param camera the device that has been disconnected
*/
- public static final int DEVICE_DISCONNECTED = 1;
+ public void onCameraDisconnected(CameraDevice camera) {
+ Log.i("CameraListener",
+ String.format("Camera device %s disconnected", camera.getId()));
+ }
/**
- * <p>The camera device has encountered a fatal error. Any attempt to
- * call methods on this CameraDevice will throw a
- * {@link java.lang.IllegalStateException}.</p>
+ * The method called when a camera device has encountered a serious error.
+ *
+ * <p>This indicates a failure of the camera device or camera service in
+ * some way. Any attempt to call methods on this CameraDevice in the
+ * future will throw a {@link java.lang.IllegalStateException}.</p>
*
* <p>There may still be capture completion or camera stream listeners
* that will be called after this error is received.</p>
*
- * <p>The application needs to re-open the camera device to use it
- * again.</p>
- */
- public static final int DEVICE_ERROR = 2;
-
- /**
- * <p>The camera service has encountered a fatal error. Any attempt to
- * call methods on this CameraDevice in the future will throw a
- * {@link java.lang.IllegalStateException}.</p>
- *
- * <p>There may still be capture completion or camera stream listeners
- * that will be called after this error is received.</p>
- *
- * <p>The device may need to be shut down and restarted to restore
- * camera function, or there may be a persistent hardware problem.</p>
- */
- public static final int SERVICE_ERROR = 3;
-
- /**
- * The method to call when a camera device has encountered an error.
+ * <p>The default implementation logs an error to the system log about
+ * the camera failure.</p>
*
* @param camera The device reporting the error
- * @param error The error code, one of the ErrorListener.ERROR_ values.
+ * @param error The error code, one of the
+ * {@code CameraDeviceListener.ERROR_*} values.
+ *
+ * @see #ERROR_CAMERA_DEVICE
+ * @see #ERROR_CAMERA_SERVICE
*/
- public void onCameraDeviceError(CameraDevice camera, int error);
+ public void onCameraError(CameraDevice camera, int error) {
+ Log.e("CameraListener",
+ String.format("Camera device %s has encountered an error: %d",
+ camera.getId(), error));
+ }
}
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index ff9282e..4ad9259 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -20,17 +20,19 @@
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.IProCameraUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.BinderHolder;
import android.os.IBinder;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.ArrayMap;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
/**
* <p>An interface for iterating, listing, and connecting to
@@ -55,7 +57,10 @@
private final ICameraService mCameraService;
private ArrayList<String> mDeviceIdList;
- private final HashSet<CameraListener> mListenerSet = new HashSet<CameraListener>();
+
+ private ArrayMap<AvailabilityListener, Handler> mListenerMap =
+ new ArrayMap<AvailabilityListener, Handler>();
+
private final Context mContext;
private final Object mLock = new Object();
@@ -85,14 +90,16 @@
}
/**
- * <p>Return the list of currently connected camera devices by
- * identifier. Non-removable cameras use integers starting at 0 for their
+ * Return the list of currently connected camera devices by
+ * identifier.
+ *
+ * <p>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.</p>
*
* @return The list of currently connected camera devices.
*/
- public String[] getDeviceIdList() throws CameraAccessException {
+ public String[] getCameraIdList() throws CameraAccessException {
synchronized (mLock) {
try {
return getOrCreateDeviceIdListLocked().toArray(new String[0]);
@@ -107,13 +114,25 @@
/**
* Register a listener to be notified about camera device availability.
*
- * Registering a listener more than once has no effect.
+ * <p>Registering the same listener again will replace the handler with the
+ * new one provided.</p>
*
* @param listener The new listener to send camera availability notices to
+ * @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}.
*/
- public void registerCameraListener(CameraListener listener) {
+ public void addAvailabilityListener(AvailabilityListener listener, Handler handler) {
+ 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);
+ }
+
synchronized (mLock) {
- mListenerSet.add(listener);
+ mListenerMap.put(listener, handler);
}
}
@@ -121,13 +140,13 @@
* Remove a previously-added listener; the listener will no longer receive
* connection and disconnection callbacks.
*
- * Removing a listener that isn't registered has no effect.
+ * <p>Removing a listener that isn't registered has no effect.</p>
*
* @param listener The listener to remove from the notification list
*/
- public void unregisterCameraListener(CameraListener listener) {
+ public void removeAvailabilityListener(AvailabilityListener listener) {
synchronized (mLock) {
- mListenerSet.remove(listener);
+ mListenerMap.remove(listener);
}
}
@@ -144,7 +163,7 @@
* @throws SecurityException if the application does not have permission to
* access the camera
*
- * @see #getDeviceIdList
+ * @see #getCameraIdList
* @see android.app.admin.DevicePolicyManager#setCameraDisabled
*/
public CameraProperties getCameraProperties(String cameraId)
@@ -160,14 +179,14 @@
// TODO: implement and call a service function to get the capabilities on C++ side
// TODO: get properties from service
- return new CameraProperties();
+ return new CameraProperties(new CameraMetadataNative());
}
/**
* Open a connection to a camera with the given ID. Use
- * {@link #getDeviceIdList} to get the list of available camera
+ * {@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 #getDeviceIdList} and
+ * is disconnected between the calls to {@link #getCameraIdList} and
* {@link #openCamera}.
*
* @param cameraId The unique identifier of the camera device to open
@@ -179,7 +198,7 @@
* @throws SecurityException if the application does not have permission to
* access the camera
*
- * @see #getDeviceIdList
+ * @see #getCameraIdList
* @see android.app.admin.DevicePolicyManager#setCameraDisabled
*/
public CameraDevice openCamera(String cameraId) throws CameraAccessException {
@@ -218,29 +237,43 @@
}
/**
- * Interface for listening to cameras becoming available or unavailable.
- * Cameras become available when they are no longer in use, or when a new
+ * Interface for listening to camera devices becoming available or
+ * unavailable.
+ *
+ * <p>Cameras become available when they are no longer in use, or when a new
* removable camera is connected. They become unavailable when some
* application or service starts using a camera, or when a removable camera
- * is disconnected.
+ * is disconnected.</p>
+ *
+ * @see addAvailabilityListener
*/
- public interface CameraListener {
+ public static abstract class AvailabilityListener {
+
/**
* A new camera has become available to use.
*
+ * <p>The default implementation of this method does nothing.</p>
+ *
* @param cameraId The unique identifier of the new camera.
*/
- public void onCameraAvailable(String cameraId);
+ public void onCameraAvailable(String cameraId) {
+ // default empty implementation
+ }
/**
- * A previously-available camera has become unavailable for use. If an
- * application had an active CameraDevice instance for the
- * now-disconnected camera, that application will receive a {@link
- * CameraDevice.ErrorListener#DEVICE_DISCONNECTED disconnection error}.
+ * A previously-available camera has become unavailable for use.
+ *
+ * <p>If an application had an active CameraDevice instance for the
+ * now-disconnected camera, that application will receive a
+ * {@link CameraDevice.CameraDeviceListener#onCameraDisconnected disconnection error}.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
*
* @param cameraId The unique identifier of the disconnected camera.
*/
- public void onCameraUnavailable(String cameraId);
+ public void onCameraUnavailable(String cameraId) {
+ // default empty implementation
+ }
}
private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
@@ -285,7 +318,7 @@
public static final int STATUS_NOT_AVAILABLE = 0x80000000;
// Camera ID -> Status map
- private final HashMap<String, Integer> mDeviceStatus = new HashMap<String, Integer>();
+ private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
private static final String TAG = "CameraServiceListener";
@@ -322,7 +355,7 @@
Log.v(TAG,
String.format("Camera id %d has status changed to 0x%x", cameraId, status));
- String id = String.valueOf(cameraId);
+ final String id = String.valueOf(cameraId);
if (!validStatus(status)) {
Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId,
@@ -363,11 +396,24 @@
return;
}
- for (CameraListener listener : mListenerSet) {
+ final int listenerCount = mListenerMap.size();
+ for (int i = 0; i < listenerCount; i++) {
+ Handler handler = mListenerMap.valueAt(i);
+ final AvailabilityListener listener = mListenerMap.keyAt(i);
if (isAvailable(status)) {
- listener.onCameraAvailable(id);
+ handler.post(
+ new Runnable() {
+ public void run() {
+ listener.onCameraAvailable(id);
+ }
+ });
} else {
- listener.onCameraUnavailable(id);
+ handler.post(
+ new Runnable() {
+ public void run() {
+ listener.onCameraUnavailable(id);
+ }
+ });
}
} // for
} // synchronized
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 70d777f..18fffc0 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -16,20 +16,7 @@
package android.hardware.camera2;
-import android.hardware.camera2.impl.MetadataMarshalClass;
-import android.hardware.camera2.impl.MetadataMarshalRect;
-import android.hardware.camera2.impl.MetadataMarshalSize;
-import android.hardware.camera2.impl.MetadataMarshalString;
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.util.Log;
-
-import java.lang.reflect.Array;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
+import android.hardware.camera2.impl.CameraMetadataNative;
/**
* The base class for camera controls and information.
@@ -42,62 +29,12 @@
* @see CameraManager
* @see CameraProperties
**/
-public class CameraMetadata implements Parcelable, AutoCloseable {
-
- public CameraMetadata() {
- mMetadataMap = new HashMap<Key<?>, Object>();
-
- mMetadataPtr = nativeAllocate();
- if (mMetadataPtr == 0) {
- throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
- }
- }
-
- public static final Parcelable.Creator<CameraMetadata> CREATOR =
- new Parcelable.Creator<CameraMetadata>() {
- @Override
- public CameraMetadata createFromParcel(Parcel in) {
- CameraMetadata metadata = new CameraMetadata();
- metadata.readFromParcel(in);
- return metadata;
- }
-
- @Override
- public CameraMetadata[] newArray(int size) {
- return new CameraMetadata[size];
- }
- };
-
- private static final String TAG = "CameraMetadataJV";
+public abstract class CameraMetadata {
/**
- * Set a camera metadata field to a value. The field definitions can be
- * found in {@link CameraProperties}, {@link CaptureResult}, and
- * {@link CaptureRequest}.
- *
- * @param key The metadata field to write.
- * @param value The value to set the field to, which must be of a matching
- * type to the key.
+ * @hide
*/
- public <T> void set(Key<T> key, T value) {
- int tag = key.getTag();
-
- if (value == null) {
- writeValues(tag, null);
- return;
- }
-
- int nativeType = getNativeType(tag);
-
- int size = packSingle(value, null, key.mType, nativeType, /* sizeOnly */true);
-
- // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
- byte[] values = new byte[size];
-
- ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
- packSingle(value, buffer, key.mType, nativeType, /*sizeOnly*/false);
-
- writeValues(tag, values);
+ protected CameraMetadata() {
}
/**
@@ -110,342 +47,16 @@
* @param key The metadata field to read.
* @return The value of that key, or {@code null} if the field is not set.
*/
- @SuppressWarnings("unchecked")
- public <T> T get(Key<T> key) {
- int tag = key.getTag();
- byte[] values = readValues(tag);
- if (values == null) {
- return null;
- }
-
- int nativeType = getNativeType(tag);
-
- ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
- return unpackSingle(buffer, key.mType, nativeType);
- }
-
- // Keep up-to-date with camera_metadata.h
- /**
- * @hide
- */
- public static final int TYPE_BYTE = 0;
- /**
- * @hide
- */
- public static final int TYPE_INT32 = 1;
- /**
- * @hide
- */
- public static final int TYPE_FLOAT = 2;
- /**
- * @hide
- */
- public static final int TYPE_INT64 = 3;
- /**
- * @hide
- */
- public static final int TYPE_DOUBLE = 4;
- /**
- * @hide
- */
- public static final int TYPE_RATIONAL = 5;
- /**
- * @hide
- */
- public static final int NUM_TYPES = 6;
-
- private static int getTypeSize(int nativeType) {
- switch(nativeType) {
- case TYPE_BYTE:
- return 1;
- case TYPE_INT32:
- case TYPE_FLOAT:
- return 4;
- case TYPE_INT64:
- case TYPE_DOUBLE:
- case TYPE_RATIONAL:
- return 8;
- }
-
- throw new UnsupportedOperationException("Unknown type, can't get size "
- + nativeType);
- }
-
- private static Class<?> getExpectedType(int nativeType) {
- switch(nativeType) {
- case TYPE_BYTE:
- return Byte.TYPE;
- case TYPE_INT32:
- return Integer.TYPE;
- case TYPE_FLOAT:
- return Float.TYPE;
- case TYPE_INT64:
- return Long.TYPE;
- case TYPE_DOUBLE:
- return Double.TYPE;
- case TYPE_RATIONAL:
- return Rational.class;
- }
-
- throw new UnsupportedOperationException("Unknown type, can't map to Java type "
- + nativeType);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
- int nativeType, boolean sizeOnly) {
-
- if (!sizeOnly) {
- /**
- * Rewrite types when the native type doesn't match the managed type
- * - Boolean -> Byte
- * - Integer -> Byte
- */
-
- if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
- // Since a boolean can't be cast to byte, and we don't want to use putBoolean
- boolean asBool = (Boolean) value;
- byte asByte = (byte) (asBool ? 1 : 0);
- value = (T) (Byte) asByte;
- } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
- int asInt = (Integer) value;
- byte asByte = (byte) asInt;
- value = (T) (Byte) asByte;
- } else if (type != getExpectedType(nativeType)) {
- throw new UnsupportedOperationException("Tried to pack a type of " + type +
- " but we expected the type to be " + getExpectedType(nativeType));
- }
-
- if (nativeType == TYPE_BYTE) {
- buffer.put((Byte) value);
- } else if (nativeType == TYPE_INT32) {
- buffer.putInt((Integer) value);
- } else if (nativeType == TYPE_FLOAT) {
- buffer.putFloat((Float) value);
- } else if (nativeType == TYPE_INT64) {
- buffer.putLong((Long) value);
- } else if (nativeType == TYPE_DOUBLE) {
- buffer.putDouble((Double) value);
- } else if (nativeType == TYPE_RATIONAL) {
- Rational r = (Rational) value;
- buffer.putInt(r.getNumerator());
- buffer.putInt(r.getDenominator());
- }
-
- }
-
- return getTypeSize(nativeType);
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- int size = 0;
-
- if (type.isPrimitive() || type == Rational.class) {
- size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
- } else if (type.isEnum()) {
- size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
- } else if (type.isArray()) {
- size = packArray(value, buffer, type, nativeType, sizeOnly);
- } else {
- size = packClass(value, buffer, type, nativeType, sizeOnly);
- }
-
- return size;
- }
-
- private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
- int nativeType, boolean sizeOnly) {
-
- // TODO: add support for enums with their own values.
- return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
- if (marshaler == null) {
- throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
- }
-
- return marshaler.marshal(value, buffer, nativeType, sizeOnly);
- }
-
- private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- int size = 0;
- int arrayLength = Array.getLength(value);
-
- @SuppressWarnings("unchecked")
- Class<Object> componentType = (Class<Object>)type.getComponentType();
-
- for (int i = 0; i < arrayLength; ++i) {
- size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
- }
-
- return size;
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- T val;
-
- if (nativeType == TYPE_BYTE) {
- val = (T) (Byte) buffer.get();
- } else if (nativeType == TYPE_INT32) {
- val = (T) (Integer) buffer.getInt();
- } else if (nativeType == TYPE_FLOAT) {
- val = (T) (Float) buffer.getFloat();
- } else if (nativeType == TYPE_INT64) {
- val = (T) (Long) buffer.getLong();
- } else if (nativeType == TYPE_DOUBLE) {
- val = (T) (Double) buffer.getDouble();
- } else if (nativeType == TYPE_RATIONAL) {
- val = (T) new Rational(buffer.getInt(), buffer.getInt());
- } else {
- throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
- + nativeType);
- }
-
- /**
- * Rewrite types when the native type doesn't match the managed type
- * - Byte -> Boolean
- * - Byte -> Integer
- */
-
- if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
- // Since a boolean can't be cast to byte, and we don't want to use getBoolean
- byte asByte = (Byte) val;
- boolean asBool = asByte != 0;
- val = (T) (Boolean) asBool;
- } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
- byte asByte = (Byte) val;
- int asInt = asByte;
- val = (T) (Integer) asInt;
- } else if (type != getExpectedType(nativeType)) {
- throw new UnsupportedOperationException("Tried to unpack a type of " + type +
- " but we expected the type to be " + getExpectedType(nativeType));
- }
-
- return val;
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- if (type.isPrimitive() || type == Rational.class) {
- return unpackSingleNative(buffer, type, nativeType);
- }
-
- if (type.isEnum()) {
- return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
- }
-
- if (type.isArray()) {
- return unpackArray(buffer, type, nativeType);
- }
-
- T instance = unpackClass(buffer, type, nativeType);
-
- return instance;
- }
-
- private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
- int nativeType) {
- int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
- return getEnumFromValue(type, ordinal);
- }
-
- private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
- if (marshaler == null) {
- throw new IllegalArgumentException("Unknown class type: " + type);
- }
-
- return marshaler.unmarshal(buffer, nativeType);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- Class<?> componentType = type.getComponentType();
- Object array;
-
- int elementSize = getTypeSize(nativeType);
-
- MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
- if (marshaler != null) {
- elementSize = marshaler.getNativeSize(nativeType);
- }
-
- if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
- int remaining = buffer.remaining();
- int arraySize = remaining / elementSize;
-
- Log.v(TAG,
- String.format(
- "Attempting to unpack array (count = %d, element size = %d, bytes " +
- "remaining = %d) for type %s",
- arraySize, elementSize, remaining, type));
-
- array = Array.newInstance(componentType, arraySize);
- for (int i = 0; i < arraySize; ++i) {
- Object elem = unpackSingle(buffer, componentType, nativeType);
- Array.set(array, i, elem);
- }
- } else {
- // Dynamic size, use an array list.
- ArrayList<Object> arrayList = new ArrayList<Object>();
-
- int primitiveSize = getTypeSize(nativeType);
- while (buffer.remaining() >= primitiveSize) {
- Object elem = unpackSingle(buffer, componentType, nativeType);
- arrayList.add(elem);
- }
-
- array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
- }
-
- if (buffer.remaining() != 0) {
- Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
- + type);
- }
-
- return (T) array;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- nativeWriteToParcel(dest);
- }
-
- /**
- * Expand this object from a Parcel.
- * @param in The Parcel from which the object should be read
- */
- public void readFromParcel(Parcel in) {
- nativeReadFromParcel(in);
- }
+ public abstract <T> T get(Key<T> key);
public static class Key<T> {
private boolean mHasTag;
private int mTag;
private final Class<T> mType;
+ private final String mName;
- /*
+ /**
* @hide
*/
public Key(String name, Class<T> type) {
@@ -483,8 +94,6 @@
return mName.equals(lhs.mName);
}
- private final String mName;
-
/**
* <p>
* Get the tag corresponding to this key. This enables insertion into the
@@ -499,267 +108,20 @@
*/
public final int getTag() {
if (!mHasTag) {
- mTag = CameraMetadata.getTag(mName);
+ mTag = CameraMetadataNative.getTag(mName);
mHasTag = true;
}
return mTag;
}
- }
- private final Map<Key<?>, Object> mMetadataMap;
-
- private long mMetadataPtr; // native CameraMetadata*
-
- private native long nativeAllocate();
- private native synchronized void nativeWriteToParcel(Parcel dest);
- private native synchronized void nativeReadFromParcel(Parcel source);
- private native synchronized void nativeSwap(CameraMetadata other) throws NullPointerException;
- private native synchronized void nativeClose();
- private native synchronized boolean nativeIsEmpty();
- private native synchronized int nativeGetEntryCount();
-
- private native synchronized byte[] nativeReadValues(int tag);
- private native synchronized void nativeWriteValues(int tag, byte[] src);
-
- private static native int nativeGetTagFromKey(String keyName)
- throws IllegalArgumentException;
- private static native int nativeGetTypeFromTag(int tag)
- throws IllegalArgumentException;
- private static native void nativeClassInit();
-
- /**
- * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
- *
- * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
- *
- * @param other Metadata to swap with
- * @throws NullPointerException if other was null
- * @hide
- */
- public void swap(CameraMetadata other) {
- nativeSwap(other);
- }
-
- /**
- * @hide
- */
- public int getEntryCount() {
- return nativeGetEntryCount();
- }
-
- /**
- * Does this metadata contain at least 1 entry?
- *
- * @hide
- */
- public boolean isEmpty() {
- return nativeIsEmpty();
- }
-
- /**
- * <p>Closes this object, and releases all native resources associated with it.</p>
- *
- * <p>Calling any other public method after this will result in an IllegalStateException
- * being thrown.</p>
- */
- @Override
- public void close() throws Exception {
- // this sets mMetadataPtr to 0
- nativeClose();
- mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
- }
-
- /**
- * Whether or not {@link #close} has already been called (at least once) on this object.
- * @hide
- */
- public boolean isClosed() {
- synchronized (this) {
- return mMetadataPtr == 0;
+ /**
+ * @hide
+ */
+ public final Class<T> getType() {
+ return mType;
}
}
- /**
- * Convert a key string into the equivalent native tag.
- *
- * @throws IllegalArgumentException if the key was not recognized
- * @throws NullPointerException if the key was null
- *
- * @hide
- */
- public static int getTag(String key) {
- return nativeGetTagFromKey(key);
- }
-
- /**
- * Get the underlying native type for a tag.
- *
- * @param tag An integer tag, see e.g. {@link #getTag}
- * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
- *
- * @hide
- */
- public static int getNativeType(int tag) {
- return nativeGetTypeFromTag(tag);
- }
-
- /**
- * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
- * the entry if src was null.</p>
- *
- * <p>An empty array can be passed in to update the entry to 0 elements.</p>
- *
- * @param tag An integer tag, see e.g. {@link #getTag}
- * @param src An array of bytes, or null to erase the entry
- *
- * @hide
- */
- public void writeValues(int tag, byte[] src) {
- nativeWriteValues(tag, src);
- }
-
- /**
- * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
- * the data properly.</p>
- *
- * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
- *
- * @param tag An integer tag, see e.g. {@link #getTag}
- *
- * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
- * @hide
- */
- public byte[] readValues(int tag) {
- // TODO: Optimization. Native code returns a ByteBuffer instead.
- return nativeReadValues(tag);
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
- private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
- new HashMap<Class<? extends Enum>, int[]>();
- /**
- * Register a non-sequential set of values to be used with the pack/unpack functions.
- * This enables get/set to correctly marshal the enum into a value that is C-compatible.
- *
- * @param enumType The class for an enum
- * @param values A list of values mapping to the ordinals of the enum
- *
- * @hide
- */
- public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
- if (enumType.getEnumConstants().length != values.length) {
- throw new IllegalArgumentException(
- "Expected values array to be the same size as the enumTypes values "
- + values.length + " for type " + enumType);
- }
-
- Log.v(TAG, "Registered enum values for type " + enumType + " values");
-
- sEnumValues.put(enumType, values);
- }
-
- /**
- * Get the numeric value from an enum. This is usually the same as the ordinal value for
- * enums that have fully sequential values, although for C-style enums the range of values
- * may not map 1:1.
- *
- * @param enumValue Enum instance
- * @return Int guaranteed to be ABI-compatible with the C enum equivalent
- */
- private static <T extends Enum<T>> int getEnumValue(T enumValue) {
- int[] values;
- values = sEnumValues.get(enumValue.getClass());
-
- int ordinal = enumValue.ordinal();
- if (values != null) {
- return values[ordinal];
- }
-
- return ordinal;
- }
-
- /**
- * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
- *
- * @param enumType Class of the enum we want to find
- * @param value The numeric value of the enum
- * @return An instance of the enum
- */
- private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
- int ordinal;
-
- int[] registeredValues = sEnumValues.get(enumType);
- if (registeredValues != null) {
- ordinal = -1;
-
- for (int i = 0; i < registeredValues.length; ++i) {
- if (registeredValues[i] == value) {
- ordinal = i;
- break;
- }
- }
- } else {
- ordinal = value;
- }
-
- T[] values = enumType.getEnumConstants();
-
- if (ordinal < 0 || ordinal >= values.length) {
- throw new IllegalArgumentException(
- String.format(
- "Argument 'value' (%d) was not a valid enum value for type %s "
- + "(registered? %b)",
- value,
- enumType, (registeredValues != null)));
- }
-
- return values[ordinal];
- }
-
- static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
- HashMap<Class<?>, MetadataMarshalClass<?>>();
-
- private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
- sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
- MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
-
- if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
- throw new UnsupportedOperationException("Unsupported type " + nativeType +
- " to be marshalled to/from a " + type);
- }
-
- return marshaler;
- }
-
- /**
- * We use a class initializer to allow the native code to cache some field offsets
- */
- static {
- System.loadLibrary("media_jni");
- nativeClassInit();
-
- Log.v(TAG, "Shall register metadata marshalers");
-
- // load built-in marshallers
- registerMarshaler(new MetadataMarshalRect());
- registerMarshaler(new MetadataMarshalSize());
- registerMarshaler(new MetadataMarshalString());
-
- Log.v(TAG, "Registered metadata marshalers");
- }
-
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The enum values below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
diff --git a/core/java/android/hardware/camera2/CameraProperties.java b/core/java/android/hardware/camera2/CameraProperties.java
index ebbdd88..45c009f 100644
--- a/core/java/android/hardware/camera2/CameraProperties.java
+++ b/core/java/android/hardware/camera2/CameraProperties.java
@@ -16,6 +16,8 @@
package android.hardware.camera2;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
/**
* <p>The properties describing a
* {@link CameraDevice CameraDevice}.</p>
@@ -29,6 +31,21 @@
*/
public final class CameraProperties extends CameraMetadata {
+ private final CameraMetadataNative mProperties;
+
+ /**
+ * Takes ownership of the passed-in properties object
+ * @hide
+ */
+ public CameraProperties(CameraMetadataNative properties) {
+ mProperties = properties;
+ }
+
+ @Override
+ public <T> T get(Key<T> key) {
+ return mProperties.get(key);
+ }
+
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The key entries below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 7735146..c3a636d 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -16,6 +16,7 @@
package android.hardware.camera2;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.Surface;
@@ -24,13 +25,16 @@
/**
- * <p>All the settings required to capture a single image from the image sensor.</p>
+ * <p>An immutable package of settings and outputs needed to capture a single
+ * image from the camera device.</p>
*
* <p>Contains the configuration for the capture hardware (sensor, lens, flash),
- * the processing pipeline, the control algorithms, and the output buffers.</p>
+ * the processing pipeline, the control algorithms, and the output buffers. Also
+ * contains the list of target Surfaces to send image data to for this
+ * capture.</p>
*
- * <p>CaptureRequests can be created by calling
- * {@link CameraDevice#createCaptureRequest}</p>
+ * <p>CaptureRequests can be created by using a {@link Builder} instance,
+ * obtained by calling {@link CameraDevice#createCaptureRequest}</p>
*
* <p>CaptureRequests are given to {@link CameraDevice#capture} or
* {@link CameraDevice#setRepeatingRequest} to capture images from a camera.</p>
@@ -38,7 +42,8 @@
* <p>Each request can specify a different subset of target Surfaces for the
* camera to send the captured data to. All the surfaces used in a request must
* be part of the surface list given to the last call to
- * {@link CameraDevice#configureOutputs}.</p>
+ * {@link CameraDevice#configureOutputs}, when the request is submitted to the
+ * camera device.</p>
*
* <p>For example, a request meant for repeating preview might only include the
* Surface for the preview SurfaceView or SurfaceTexture, while a
@@ -47,64 +52,43 @@
*
* @see CameraDevice#capture
* @see CameraDevice#setRepeatingRequest
- * @see CameraDevice#createRequest
+ * @see CameraDevice#createCaptureRequest
*/
public final class CaptureRequest extends CameraMetadata implements Parcelable {
- private final Object mLock = new Object();
- private final HashSet<Surface> mSurfaceSet = new HashSet<Surface>();
+ private final HashSet<Surface> mSurfaceSet;
+ private final CameraMetadataNative mSettings;
+
private Object mUserTag;
/**
+ * Construct empty request
* @hide
*/
public CaptureRequest() {
+ mSettings = new CameraMetadataNative();
+ mSurfaceSet = new HashSet<Surface>();
}
/**
- * <p>Add a surface to the list of targets for this request</p>
- *
- * <p>The Surface added must be one of the surfaces included in the last
- * call to {@link CameraDevice#configureOutputs}.</p>
- *
- * <p>Adding a target more than once has no effect.</p>
- *
- * @param outputTarget Surface to use as an output target for this request
+ * Clone from source capture request
*/
- public void addTarget(Surface outputTarget) {
- synchronized (mLock) {
- mSurfaceSet.add(outputTarget);
- }
+ private CaptureRequest(CaptureRequest source) {
+ mSettings = new CameraMetadataNative(source.mSettings);
+ mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone();
}
/**
- * <p>Remove a surface from the list of targets for this request.</p>
- *
- * <p>Removing a target that is not currently added has no effect.</p>
- *
- * @param outputTarget Surface to use as an output target for this request
+ * Take ownership of passed-in settings
*/
- public void removeTarget(Surface outputTarget) {
- synchronized (mLock) {
- mSurfaceSet.remove(outputTarget);
- }
+ private CaptureRequest(CameraMetadataNative settings) {
+ mSettings = settings;
+ mSurfaceSet = new HashSet<Surface>();
}
- /**
- * Set a tag for this request.
- *
- * <p>This tag is not used for anything by the camera device, but can be
- * used by an application to easily identify a CaptureRequest when it is
- * returned by
- * {@link CameraDevice.CaptureListener#onCaptureComplete CaptureListener.onCaptureComplete}
- *
- * @param tag an arbitrary Object to store with this request
- * @see #getTag
- */
- public void setTag(Object tag) {
- synchronized (mLock) {
- mUserTag = tag;
- }
+ @Override
+ public <T> T get(Key<T> key) {
+ return mSettings.get(key);
}
/**
@@ -113,17 +97,15 @@
* <p>This tag is not used for anything by the camera device, but can be
* used by an application to easily identify a CaptureRequest when it is
* returned by
- * {@link CameraDevice.CaptureListener#onCaptureComplete CaptureListener.onCaptureComplete}
+ * {@link CameraDevice.CaptureListener#onCaptureCompleted CaptureListener.onCaptureCompleted}
* </p>
*
* @return the last tag Object set on this request, or {@code null} if
* no tag has been set.
- * @see #setTag
+ * @see Builder#setTag
*/
public Object getTag() {
- synchronized (mLock) {
- return mUserTag;
- }
+ return mUserTag;
}
public static final Parcelable.Creator<CaptureRequest> CREATOR =
@@ -132,6 +114,7 @@
public CaptureRequest createFromParcel(Parcel in) {
CaptureRequest request = new CaptureRequest();
request.readFromParcel(in);
+
return request;
}
@@ -143,35 +126,152 @@
/**
* Expand this object from a Parcel.
+ * Hidden since this breaks the immutability of CaptureRequest, but is
+ * needed to receive CaptureRequests with aidl.
+ *
* @param in The parcel from which the object should be read
+ * @hide
*/
- @Override
public void readFromParcel(Parcel in) {
- synchronized (mLock) {
- super.readFromParcel(in);
+ mSettings.readFromParcel(in);
- mSurfaceSet.clear();
+ mSurfaceSet.clear();
- Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader());
+ Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader());
- if (parcelableArray == null) {
- return;
- }
+ if (parcelableArray == null) {
+ return;
+ }
- for (Parcelable p : parcelableArray) {
- Surface s = (Surface) p;
- mSurfaceSet.add(s);
- }
+ for (Parcelable p : parcelableArray) {
+ Surface s = (Surface) p;
+ mSurfaceSet.add(s);
}
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- synchronized (mLock) {
- super.writeToParcel(dest, flags);
+ public int describeContents() {
+ return 0;
+ }
- dest.writeParcelableArray(mSurfaceSet.toArray(new Surface[mSurfaceSet.size()]), flags);
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mSettings.writeToParcel(dest, flags);
+ dest.writeParcelableArray(mSurfaceSet.toArray(new Surface[mSurfaceSet.size()]), flags);
+ }
+
+ /**
+ * A builder for capture requests.
+ *
+ * <p>To obtain a builder instance, use the
+ * {@link CameraDevice#createCaptureRequest} method, which initializes the
+ * request fields to one of the templates defined in {@link CameraDevice}.
+ *
+ * @see CameraDevice#createCaptureRequest
+ * @see #TEMPLATE_PREVIEW
+ * @see #TEMPLATE_RECORD
+ * @see #TEMPLATE_STILL_CAPTURE
+ * @see #TEMPLATE_VIDEO_SNAPSHOT
+ * @see #TEMPLATE_MANUAL
+ */
+ public final static class Builder {
+
+ private CaptureRequest mRequest;
+
+ /**
+ * Initialize the builder using the template; the request takes
+ * ownership of the template.
+ *
+ * @hide
+ */
+ public Builder(CameraMetadataNative template) {
+ mRequest = new CaptureRequest(template);
}
+
+ /**
+ * <p>Add a surface to the list of targets for this request</p>
+ *
+ * <p>The Surface added must be one of the surfaces included in the most
+ * recent call to {@link CameraDevice#configureOutputs}, when the
+ * request is given to the camera device.</p>
+ *
+ * <p>Adding a target more than once has no effect.</p>
+ *
+ * @param outputTarget Surface to use as an output target for this request
+ */
+ public void addTarget(Surface outputTarget) {
+ mRequest.mSurfaceSet.add(outputTarget);
+ }
+
+ /**
+ * <p>Remove a surface from the list of targets for this request.</p>
+ *
+ * <p>Removing a target that is not currently added has no effect.</p>
+ *
+ * @param outputTarget Surface to use as an output target for this request
+ */
+ public void removeTarget(Surface outputTarget) {
+ mRequest.mSurfaceSet.remove(outputTarget);
+ }
+
+ /**
+ * Set a capture request field to a value. The field definitions can be
+ * found in {@link CaptureRequest}.
+ *
+ * @param key The metadata field to write.
+ * @param value The value to set the field to, which must be of a matching
+ * type to the key.
+ */
+ public <T> void set(Key<T> key, T value) {
+ mRequest.mSettings.set(key, value);
+ }
+
+ /**
+ * Get a capture request field value. The field definitions can be
+ * found in {@link CaptureRequest}.
+ *
+ * @throws IllegalArgumentException if the key was not valid
+ *
+ * @param key The metadata field to read.
+ * @return The value of that key, or {@code null} if the field is not set.
+ */
+ public <T> T get(Key<T> key) {
+ return mRequest.mSettings.get(key);
+ }
+
+ /**
+ * Set a tag for this request.
+ *
+ * <p>This tag is not used for anything by the camera device, but can be
+ * used by an application to easily identify a CaptureRequest when it is
+ * returned by
+ * {@link CameraDevice.CaptureListener#onCaptureCompleted CaptureListener.onCaptureCompleted}
+ *
+ * @param tag an arbitrary Object to store with this request
+ * @see CaptureRequest#getTag
+ */
+ public void setTag(Object tag) {
+ mRequest.mUserTag = tag;
+ }
+
+ /**
+ * Build a request using the current target Surfaces and settings.
+ *
+ * @return A new capture request instance, ready for submission to the
+ * camera device.
+ */
+ public CaptureRequest build() {
+ return new CaptureRequest(mRequest);
+ }
+
+
+ /**
+ * @hide
+ */
+ public boolean isEmpty() {
+ return mRequest.mSettings.isEmpty();
+ }
+
}
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index bd151a2..f83dad7 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -18,6 +18,7 @@
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.camera2.impl.CameraMetadataNative;
/**
* <p>The results of a single image capture from the image sensor.</p>
@@ -34,10 +35,20 @@
*
*/
public final class CaptureResult extends CameraMetadata {
+
+ private final CameraMetadataNative mResults;
+
/**
+ * Takes ownership of the passed-in properties object
* @hide
*/
- public CaptureResult() {
+ public CaptureResult(CameraMetadataNative results) {
+ mResults = results;
+ }
+
+ @Override
+ public <T> T get(Key<T> key) {
+ return mResults.get(key);
}
/**
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 4172238..4054a92 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -16,7 +16,7 @@
package android.hardware.camera2;
-import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.impl.CameraMetadataNative;
/** @hide */
interface ICameraDeviceCallbacks
@@ -26,5 +26,5 @@
*/
oneway void notifyCallback(int msgType, int ext1, int ext2);
- oneway void onResultReceived(int frameId, in CameraMetadata result);
+ oneway void onResultReceived(int frameId, in CameraMetadataNative result);
}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index b1724de..1936963 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -17,7 +17,7 @@
package android.hardware.camera2;
import android.view.Surface;
-import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.CaptureRequest;
/** @hide */
@@ -40,9 +40,9 @@
// non-negative value is the stream ID. negative value is status_t
int createStream(int width, int height, int format, in Surface surface);
- int createDefaultRequest(int templateId, out CameraMetadata request);
+ int createDefaultRequest(int templateId, out CameraMetadataNative request);
- int getCameraInfo(out CameraMetadata info);
+ int getCameraInfo(out CameraMetadataNative info);
int waitUntilIdle();
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 86a073f..995555a 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -29,6 +29,8 @@
import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
@@ -40,7 +42,7 @@
import java.util.Stack;
/**
- * HAL2.1+ implementation of CameraDevice Use CameraManager#open to instantiate
+ * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
*/
public class CameraDevice implements android.hardware.camera2.CameraDevice {
@@ -53,10 +55,11 @@
private final Object mLock = new Object();
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
- // XX: Make this a WeakReference<CaptureListener> ?
- // TODO: Convert to SparseIntArray
- private final HashMap<Integer, CaptureListenerHolder> mCaptureListenerMap =
- new HashMap<Integer, CaptureListenerHolder>();
+ private CameraDeviceListener mDeviceListener;
+ private Handler mDeviceHandler;
+
+ private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
+ new SparseArray<CaptureListenerHolder>();
private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
// Map stream IDs to Surfaces
@@ -80,10 +83,14 @@
}
@Override
+ public String getId() {
+ return mCameraId;
+ }
+
+ @Override
public CameraProperties getProperties() throws CameraAccessException {
- CameraProperties properties = new CameraProperties();
- CameraMetadata info = new CameraMetadata();
+ CameraMetadataNative info = new CameraMetadataNative();
try {
mRemoteDevice.getCameraInfo(/*out*/info);
@@ -94,7 +101,7 @@
return null;
}
- properties.swap(info);
+ CameraProperties properties = new CameraProperties(info);
return properties;
}
@@ -149,11 +156,11 @@
}
@Override
- public CaptureRequest createCaptureRequest(int templateType) throws CameraAccessException {
-
+ public CaptureRequest.Builder createCaptureRequest(int templateType)
+ throws CameraAccessException {
synchronized (mLock) {
- CameraMetadata templatedRequest = new CameraMetadata();
+ CameraMetadataNative templatedRequest = new CameraMetadataNative();
try {
mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
@@ -164,23 +171,22 @@
return null;
}
- CaptureRequest request = new CaptureRequest();
- request.swap(templatedRequest);
+ CaptureRequest.Builder builder =
+ new CaptureRequest.Builder(templatedRequest);
- return request;
-
+ return builder;
}
}
@Override
- public void capture(CaptureRequest request, CaptureListener listener)
+ public void capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException {
- submitCaptureRequest(request, listener, /*streaming*/false);
+ submitCaptureRequest(request, listener, handler, /*streaming*/false);
}
@Override
- public void captureBurst(List<CaptureRequest> requests, CaptureListener listener)
- throws CameraAccessException {
+ public void captureBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException {
if (requests.isEmpty()) {
Log.w(TAG, "Capture burst request list is empty, do nothing!");
return;
@@ -191,7 +197,18 @@
}
private void submitCaptureRequest(CaptureRequest request, CaptureListener listener,
- boolean repeating) throws CameraAccessException {
+ Handler handler, boolean repeating) throws CameraAccessException {
+
+ // Need a valid handler, or current thread needs to have a looper, if
+ // listener is valid
+ if (handler == null && listener != null) {
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ throw new IllegalArgumentException(
+ "No handler given, and current thread has no looper!");
+ }
+ handler = new Handler(looper);
+ }
synchronized (mLock) {
@@ -205,9 +222,10 @@
// impossible
return;
}
-
- mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
- repeating));
+ if (listener != null) {
+ mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
+ handler, repeating));
+ }
if (repeating) {
mRepeatingRequestIdStack.add(requestId);
@@ -217,14 +235,14 @@
}
@Override
- public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
- throws CameraAccessException {
- submitCaptureRequest(request, listener, /*streaming*/true);
+ public void setRepeatingRequest(CaptureRequest request, CaptureListener listener,
+ Handler handler) throws CameraAccessException {
+ submitCaptureRequest(request, listener, handler, /*streaming*/true);
}
@Override
- public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
- throws CameraAccessException {
+ public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException {
if (requests.isEmpty()) {
Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
return;
@@ -274,9 +292,11 @@
}
@Override
- public void setErrorListener(ErrorListener listener) {
- // TODO Auto-generated method stub
-
+ public void setDeviceListener(CameraDeviceListener listener, Handler handler) {
+ synchronized (mLock) {
+ mDeviceListener = listener;
+ mDeviceHandler = handler;
+ }
}
@Override
@@ -332,9 +352,16 @@
private final boolean mRepeating;
private final CaptureListener mListener;
private final CaptureRequest mRequest;
+ private final Handler mHandler;
- CaptureListenerHolder(CaptureListener listener, CaptureRequest request, boolean repeating) {
+ CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
+ boolean repeating) {
+ if (listener == null || handler == null) {
+ throw new UnsupportedOperationException(
+ "Must have a valid handler and a valid listener");
+ }
mRepeating = repeating;
+ mHandler = handler;
mRequest = request;
mListener = listener;
}
@@ -350,6 +377,11 @@
public CaptureRequest getRequest() {
return mRequest;
}
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
}
// TODO: unit tests
@@ -370,11 +402,12 @@
}
@Override
- public void onResultReceived(int requestId, CameraMetadata result) throws RemoteException {
+ public void onResultReceived(int requestId, CameraMetadataNative result)
+ throws RemoteException {
if (DEBUG) {
Log.d(TAG, "Received result for id " + requestId);
}
- CaptureListenerHolder holder;
+ final CaptureListenerHolder holder;
synchronized (mLock) {
// TODO: move this whole map into this class to make it more testable,
@@ -393,18 +426,22 @@
}
}
+ // Check if we have a listener for this
if (holder == null) {
- Log.e(TAG, "Result had no listener holder associated with it, dropping result");
return;
}
- CaptureResult resultAsCapture = new CaptureResult();
- resultAsCapture.swap(result);
+ final CaptureResult resultAsCapture = new CaptureResult(result);
- if (holder.getListener() != null) {
- holder.getListener().onCaptureComplete(CameraDevice.this, holder.getRequest(),
- resultAsCapture);
- }
+ holder.getHandler().post(
+ new Runnable() {
+ public void run() {
+ holder.getListener().onCaptureCompleted(
+ CameraDevice.this,
+ holder.getRequest(),
+ resultAsCapture);
+ }
+ });
}
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.aidl b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
similarity index 89%
rename from core/java/android/hardware/camera2/CameraMetadata.aidl
rename to core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
index 71dd471..4a89129 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.aidl
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
/** @hide */
-parcelable CameraMetadata;
+parcelable CameraMetadataNative;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
new file mode 100644
index 0000000..020d7b6
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2013 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.impl;
+
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.Rational;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of camera metadata marshal/unmarshal across Binder to
+ * the camera service
+ */
+public class CameraMetadataNative extends CameraMetadata implements Parcelable {
+
+ private static final String TAG = "CameraMetadataJV";
+
+ public CameraMetadataNative() {
+ super();
+ mMetadataPtr = nativeAllocate();
+ if (mMetadataPtr == 0) {
+ throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
+ }
+ }
+
+ /**
+ * Copy constructor - clone metadata
+ */
+ public CameraMetadataNative(CameraMetadataNative other) {
+ super();
+ mMetadataPtr = nativeAllocateCopy(other);
+ if (mMetadataPtr == 0) {
+ throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
+ }
+ }
+
+ public static final Parcelable.Creator<CameraMetadataNative> CREATOR =
+ new Parcelable.Creator<CameraMetadataNative>() {
+ @Override
+ public CameraMetadataNative createFromParcel(Parcel in) {
+ CameraMetadataNative metadata = new CameraMetadataNative();
+ metadata.readFromParcel(in);
+ return metadata;
+ }
+
+ @Override
+ public CameraMetadataNative[] newArray(int size) {
+ return new CameraMetadataNative[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ nativeWriteToParcel(dest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T get(Key<T> key) {
+ int tag = key.getTag();
+ byte[] values = readValues(tag);
+ if (values == null) {
+ return null;
+ }
+
+ int nativeType = getNativeType(tag);
+
+ ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
+ return unpackSingle(buffer, key.getType(), nativeType);
+ }
+
+ public void readFromParcel(Parcel in) {
+ nativeReadFromParcel(in);
+ }
+
+ /**
+ * Set a camera metadata field to a value. The field definitions can be
+ * found in {@link CameraProperties}, {@link CaptureResult}, and
+ * {@link CaptureRequest}.
+ *
+ * @param key The metadata field to write.
+ * @param value The value to set the field to, which must be of a matching
+ * type to the key.
+ */
+ public <T> void set(Key<T> key, T value) {
+ int tag = key.getTag();
+
+ if (value == null) {
+ writeValues(tag, null);
+ return;
+ }
+
+ int nativeType = getNativeType(tag);
+
+ int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true);
+
+ // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
+ byte[] values = new byte[size];
+
+ ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
+ packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false);
+
+ writeValues(tag, values);
+ }
+
+ // Keep up-to-date with camera_metadata.h
+ /**
+ * @hide
+ */
+ public static final int TYPE_BYTE = 0;
+ /**
+ * @hide
+ */
+ public static final int TYPE_INT32 = 1;
+ /**
+ * @hide
+ */
+ public static final int TYPE_FLOAT = 2;
+ /**
+ * @hide
+ */
+ public static final int TYPE_INT64 = 3;
+ /**
+ * @hide
+ */
+ public static final int TYPE_DOUBLE = 4;
+ /**
+ * @hide
+ */
+ public static final int TYPE_RATIONAL = 5;
+ /**
+ * @hide
+ */
+ public static final int NUM_TYPES = 6;
+
+ private void close() {
+ // this sets mMetadataPtr to 0
+ nativeClose();
+ mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
+ }
+
+ private static int getTypeSize(int nativeType) {
+ switch(nativeType) {
+ case TYPE_BYTE:
+ return 1;
+ case TYPE_INT32:
+ case TYPE_FLOAT:
+ return 4;
+ case TYPE_INT64:
+ case TYPE_DOUBLE:
+ case TYPE_RATIONAL:
+ return 8;
+ }
+
+ throw new UnsupportedOperationException("Unknown type, can't get size "
+ + nativeType);
+ }
+
+ private static Class<?> getExpectedType(int nativeType) {
+ switch(nativeType) {
+ case TYPE_BYTE:
+ return Byte.TYPE;
+ case TYPE_INT32:
+ return Integer.TYPE;
+ case TYPE_FLOAT:
+ return Float.TYPE;
+ case TYPE_INT64:
+ return Long.TYPE;
+ case TYPE_DOUBLE:
+ return Double.TYPE;
+ case TYPE_RATIONAL:
+ return Rational.class;
+ }
+
+ throw new UnsupportedOperationException("Unknown type, can't map to Java type "
+ + nativeType);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
+ int nativeType, boolean sizeOnly) {
+
+ if (!sizeOnly) {
+ /**
+ * Rewrite types when the native type doesn't match the managed type
+ * - Boolean -> Byte
+ * - Integer -> Byte
+ */
+
+ if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
+ // Since a boolean can't be cast to byte, and we don't want to use putBoolean
+ boolean asBool = (Boolean) value;
+ byte asByte = (byte) (asBool ? 1 : 0);
+ value = (T) (Byte) asByte;
+ } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
+ int asInt = (Integer) value;
+ byte asByte = (byte) asInt;
+ value = (T) (Byte) asByte;
+ } else if (type != getExpectedType(nativeType)) {
+ throw new UnsupportedOperationException("Tried to pack a type of " + type +
+ " but we expected the type to be " + getExpectedType(nativeType));
+ }
+
+ if (nativeType == TYPE_BYTE) {
+ buffer.put((Byte) value);
+ } else if (nativeType == TYPE_INT32) {
+ buffer.putInt((Integer) value);
+ } else if (nativeType == TYPE_FLOAT) {
+ buffer.putFloat((Float) value);
+ } else if (nativeType == TYPE_INT64) {
+ buffer.putLong((Long) value);
+ } else if (nativeType == TYPE_DOUBLE) {
+ buffer.putDouble((Double) value);
+ } else if (nativeType == TYPE_RATIONAL) {
+ Rational r = (Rational) value;
+ buffer.putInt(r.getNumerator());
+ buffer.putInt(r.getDenominator());
+ }
+
+ }
+
+ return getTypeSize(nativeType);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+ boolean sizeOnly) {
+
+ int size = 0;
+
+ if (type.isPrimitive() || type == Rational.class) {
+ size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
+ } else if (type.isEnum()) {
+ size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
+ } else if (type.isArray()) {
+ size = packArray(value, buffer, type, nativeType, sizeOnly);
+ } else {
+ size = packClass(value, buffer, type, nativeType, sizeOnly);
+ }
+
+ return size;
+ }
+
+ private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
+ int nativeType, boolean sizeOnly) {
+
+ // TODO: add support for enums with their own values.
+ return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+ boolean sizeOnly) {
+
+ MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+ if (marshaler == null) {
+ throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
+ }
+
+ return marshaler.marshal(value, buffer, nativeType, sizeOnly);
+ }
+
+ private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+ boolean sizeOnly) {
+
+ int size = 0;
+ int arrayLength = Array.getLength(value);
+
+ @SuppressWarnings("unchecked")
+ Class<Object> componentType = (Class<Object>)type.getComponentType();
+
+ for (int i = 0; i < arrayLength; ++i) {
+ size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
+ }
+
+ return size;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ T val;
+
+ if (nativeType == TYPE_BYTE) {
+ val = (T) (Byte) buffer.get();
+ } else if (nativeType == TYPE_INT32) {
+ val = (T) (Integer) buffer.getInt();
+ } else if (nativeType == TYPE_FLOAT) {
+ val = (T) (Float) buffer.getFloat();
+ } else if (nativeType == TYPE_INT64) {
+ val = (T) (Long) buffer.getLong();
+ } else if (nativeType == TYPE_DOUBLE) {
+ val = (T) (Double) buffer.getDouble();
+ } else if (nativeType == TYPE_RATIONAL) {
+ val = (T) new Rational(buffer.getInt(), buffer.getInt());
+ } else {
+ throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
+ + nativeType);
+ }
+
+ /**
+ * Rewrite types when the native type doesn't match the managed type
+ * - Byte -> Boolean
+ * - Byte -> Integer
+ */
+
+ if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
+ // Since a boolean can't be cast to byte, and we don't want to use getBoolean
+ byte asByte = (Byte) val;
+ boolean asBool = asByte != 0;
+ val = (T) (Boolean) asBool;
+ } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
+ byte asByte = (Byte) val;
+ int asInt = asByte;
+ val = (T) (Integer) asInt;
+ } else if (type != getExpectedType(nativeType)) {
+ throw new UnsupportedOperationException("Tried to unpack a type of " + type +
+ " but we expected the type to be " + getExpectedType(nativeType));
+ }
+
+ return val;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ if (type.isPrimitive() || type == Rational.class) {
+ return unpackSingleNative(buffer, type, nativeType);
+ }
+
+ if (type.isEnum()) {
+ return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
+ }
+
+ if (type.isArray()) {
+ return unpackArray(buffer, type, nativeType);
+ }
+
+ T instance = unpackClass(buffer, type, nativeType);
+
+ return instance;
+ }
+
+ private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
+ int nativeType) {
+ int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
+ return getEnumFromValue(type, ordinal);
+ }
+
+ private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+ if (marshaler == null) {
+ throw new IllegalArgumentException("Unknown class type: " + type);
+ }
+
+ return marshaler.unmarshal(buffer, nativeType);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ Class<?> componentType = type.getComponentType();
+ Object array;
+
+ int elementSize = getTypeSize(nativeType);
+
+ MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
+ if (marshaler != null) {
+ elementSize = marshaler.getNativeSize(nativeType);
+ }
+
+ if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
+ int remaining = buffer.remaining();
+ int arraySize = remaining / elementSize;
+
+ Log.v(TAG,
+ String.format(
+ "Attempting to unpack array (count = %d, element size = %d, bytes " +
+ "remaining = %d) for type %s",
+ arraySize, elementSize, remaining, type));
+
+ array = Array.newInstance(componentType, arraySize);
+ for (int i = 0; i < arraySize; ++i) {
+ Object elem = unpackSingle(buffer, componentType, nativeType);
+ Array.set(array, i, elem);
+ }
+ } else {
+ // Dynamic size, use an array list.
+ ArrayList<Object> arrayList = new ArrayList<Object>();
+
+ int primitiveSize = getTypeSize(nativeType);
+ while (buffer.remaining() >= primitiveSize) {
+ Object elem = unpackSingle(buffer, componentType, nativeType);
+ arrayList.add(elem);
+ }
+
+ array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
+ }
+
+ if (buffer.remaining() != 0) {
+ Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
+ + type);
+ }
+
+ return (T) array;
+ }
+
+ private long mMetadataPtr; // native CameraMetadata*
+
+ private native long nativeAllocate();
+ private native long nativeAllocateCopy(CameraMetadataNative other)
+ throws NullPointerException;
+
+ private native synchronized void nativeWriteToParcel(Parcel dest);
+ private native synchronized void nativeReadFromParcel(Parcel source);
+ private native synchronized void nativeSwap(CameraMetadataNative other)
+ throws NullPointerException;
+ private native synchronized void nativeClose();
+ private native synchronized boolean nativeIsEmpty();
+ private native synchronized int nativeGetEntryCount();
+
+ private native synchronized byte[] nativeReadValues(int tag);
+ private native synchronized void nativeWriteValues(int tag, byte[] src);
+
+ private static native int nativeGetTagFromKey(String keyName)
+ throws IllegalArgumentException;
+ private static native int nativeGetTypeFromTag(int tag)
+ throws IllegalArgumentException;
+ private static native void nativeClassInit();
+
+ /**
+ * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
+ *
+ * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
+ *
+ * @param other Metadata to swap with
+ * @throws NullPointerException if other was null
+ * @hide
+ */
+ public void swap(CameraMetadataNative other) {
+ nativeSwap(other);
+ }
+
+ /**
+ * @hide
+ */
+ public int getEntryCount() {
+ return nativeGetEntryCount();
+ }
+
+ /**
+ * Does this metadata contain at least 1 entry?
+ *
+ * @hide
+ */
+ public boolean isEmpty() {
+ return nativeIsEmpty();
+ }
+
+ /**
+ * Convert a key string into the equivalent native tag.
+ *
+ * @throws IllegalArgumentException if the key was not recognized
+ * @throws NullPointerException if the key was null
+ *
+ * @hide
+ */
+ public static int getTag(String key) {
+ return nativeGetTagFromKey(key);
+ }
+
+ /**
+ * Get the underlying native type for a tag.
+ *
+ * @param tag An integer tag, see e.g. {@link #getTag}
+ * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
+ *
+ * @hide
+ */
+ public static int getNativeType(int tag) {
+ return nativeGetTypeFromTag(tag);
+ }
+
+ /**
+ * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
+ * the entry if src was null.</p>
+ *
+ * <p>An empty array can be passed in to update the entry to 0 elements.</p>
+ *
+ * @param tag An integer tag, see e.g. {@link #getTag}
+ * @param src An array of bytes, or null to erase the entry
+ *
+ * @hide
+ */
+ public void writeValues(int tag, byte[] src) {
+ nativeWriteValues(tag, src);
+ }
+
+ /**
+ * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
+ * the data properly.</p>
+ *
+ * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
+ *
+ * @param tag An integer tag, see e.g. {@link #getTag}
+ *
+ * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
+ * @hide
+ */
+ public byte[] readValues(int tag) {
+ // TODO: Optimization. Native code returns a ByteBuffer instead.
+ return nativeReadValues(tag);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
+ new HashMap<Class<? extends Enum>, int[]>();
+ /**
+ * Register a non-sequential set of values to be used with the pack/unpack functions.
+ * This enables get/set to correctly marshal the enum into a value that is C-compatible.
+ *
+ * @param enumType The class for an enum
+ * @param values A list of values mapping to the ordinals of the enum
+ *
+ * @hide
+ */
+ public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
+ if (enumType.getEnumConstants().length != values.length) {
+ throw new IllegalArgumentException(
+ "Expected values array to be the same size as the enumTypes values "
+ + values.length + " for type " + enumType);
+ }
+
+ Log.v(TAG, "Registered enum values for type " + enumType + " values");
+
+ sEnumValues.put(enumType, values);
+ }
+
+ /**
+ * Get the numeric value from an enum. This is usually the same as the ordinal value for
+ * enums that have fully sequential values, although for C-style enums the range of values
+ * may not map 1:1.
+ *
+ * @param enumValue Enum instance
+ * @return Int guaranteed to be ABI-compatible with the C enum equivalent
+ */
+ private static <T extends Enum<T>> int getEnumValue(T enumValue) {
+ int[] values;
+ values = sEnumValues.get(enumValue.getClass());
+
+ int ordinal = enumValue.ordinal();
+ if (values != null) {
+ return values[ordinal];
+ }
+
+ return ordinal;
+ }
+
+ /**
+ * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
+ *
+ * @param enumType Class of the enum we want to find
+ * @param value The numeric value of the enum
+ * @return An instance of the enum
+ */
+ private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
+ int ordinal;
+
+ int[] registeredValues = sEnumValues.get(enumType);
+ if (registeredValues != null) {
+ ordinal = -1;
+
+ for (int i = 0; i < registeredValues.length; ++i) {
+ if (registeredValues[i] == value) {
+ ordinal = i;
+ break;
+ }
+ }
+ } else {
+ ordinal = value;
+ }
+
+ T[] values = enumType.getEnumConstants();
+
+ if (ordinal < 0 || ordinal >= values.length) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Argument 'value' (%d) was not a valid enum value for type %s "
+ + "(registered? %b)",
+ value,
+ enumType, (registeredValues != null)));
+ }
+
+ return values[ordinal];
+ }
+
+ static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
+ HashMap<Class<?>, MetadataMarshalClass<?>>();
+
+ private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
+ sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
+ MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
+
+ if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
+ throw new UnsupportedOperationException("Unsupported type " + nativeType +
+ " to be marshalled to/from a " + type);
+ }
+
+ return marshaler;
+ }
+
+ /**
+ * We use a class initializer to allow the native code to cache some field offsets
+ */
+ static {
+ System.loadLibrary("media_jni");
+ nativeClassInit();
+
+ Log.v(TAG, "Shall register metadata marshalers");
+
+ // load built-in marshallers
+ registerMarshaler(new MetadataMarshalRect());
+ registerMarshaler(new MetadataMarshalSize());
+ registerMarshaler(new MetadataMarshalString());
+
+ Log.v(TAG, "Registered metadata marshalers");
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
index a934d75..6d224ef 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
@@ -26,7 +26,7 @@
* @param value the value of type T that we wish to write into the byte buffer
* @param buffer the byte buffer into which the marshalled object will be written
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
* Guaranteed to be one for which isNativeTypeSupported returns true.
* @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
* @return the size that needs to be written to the byte buffer
@@ -37,7 +37,7 @@
* Unmarshal a new object instance from the byte buffer.
* @param buffer the byte buffer, from which we will read the object
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
* Guaranteed to be one for which isNativeTypeSupported returns true.
* @return a new instance of type T read from the byte buffer
*/
@@ -50,7 +50,7 @@
* will are likely to only support one type.
*
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
* @return true if it supports, false otherwise
*/
boolean isNativeTypeSupported(int nativeType);
@@ -60,7 +60,7 @@
/**
* How many bytes T will take up if marshalled to/from nativeType
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
* @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
*/
int getNativeSize(int nativeType);
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
index 384223c..ab72c4f 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
@@ -16,7 +16,6 @@
package android.hardware.camera2.impl;
import android.graphics.Rect;
-import android.hardware.camera2.CameraMetadata;
import java.nio.ByteBuffer;
@@ -58,7 +57,7 @@
@Override
public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadata.TYPE_INT32;
+ return nativeType == CameraMetadataNative.TYPE_INT32;
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
index 793bba7..e8143e0 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
@@ -15,7 +15,6 @@
*/
package android.hardware.camera2.impl;
-import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.Size;
import java.nio.ByteBuffer;
@@ -51,7 +50,7 @@
@Override
public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadata.TYPE_INT32;
+ return nativeType == CameraMetadataNative.TYPE_INT32;
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
index 50b3347..b61b8d3 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
@@ -15,8 +15,6 @@
*/
package android.hardware.camera2.impl;
-import android.hardware.camera2.CameraMetadata;
-
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
@@ -71,7 +69,7 @@
@Override
public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadata.TYPE_BYTE;
+ return nativeType == CameraMetadataNative.TYPE_BYTE;
}
@Override
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 0bebc04..a0d39ca 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -159,6 +159,7 @@
private static final long TOUCH_STABILIZE_TIME = 128; // ms
private static final int DOUBLE_TAP_MODE_NONE = 0;
private static final int DOUBLE_TAP_MODE_IN_PROGRESS = 1;
+ private static final float SCALE_FACTOR = .5f;
/**
@@ -197,7 +198,7 @@
* @throws NullPointerException if {@code listener} is null.
*/
public ScaleGestureDetector(Context context, OnScaleGestureListener listener,
- Handler handler) {
+ Handler handler) {
mContext = context;
mListener = listener;
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
@@ -409,7 +410,9 @@
mPrevSpanY = mCurrSpanY = spanY;
mInitialSpan = mPrevSpan = mCurrSpan = span;
}
- if (!mInProgress && span >= mMinSpan &&
+
+ final int minSpan = inDoubleTapMode() ? mSpanSlop : mMinSpan;
+ if (!mInProgress && span >= minSpan &&
(wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) {
mPrevSpanX = mCurrSpanX = spanX;
mPrevSpanY = mCurrSpanY = spanY;
@@ -464,7 +467,7 @@
mDoubleTapMode = DOUBLE_TAP_MODE_IN_PROGRESS;
return true;
}
- };
+ };
mGestureDetector = new GestureDetector(mContext, gestureListener, mHandler);
}
}
@@ -572,11 +575,15 @@
* @return The current scaling factor.
*/
public float getScaleFactor() {
- if (inDoubleTapMode() && mEventBeforeOrAboveStartingGestureEvent) {
+ if (inDoubleTapMode()) {
// Drag is moving up; the further away from the gesture
// start, the smaller the span should be, the closer,
// the larger the span, and therefore the larger the scale
- return (1 / mCurrSpan) / (1 / mPrevSpan);
+ final boolean scaleUp =
+ (mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan < mPrevSpan)) ||
+ (!mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan > mPrevSpan));
+ final float spanDiff = (Math.abs(1 - (mCurrSpan / mPrevSpan)) * SCALE_FACTOR);
+ return mPrevSpan <= 0 ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff);
}
return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
}
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index f70f0d1..6e496fd 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -19,6 +19,7 @@
#include <jni.h>
#include <JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <utils/String8.h>
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 852c4d4..3c7da1e 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -38,7 +38,7 @@
#endif
// fully-qualified class name
-#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/CameraMetadata"
+#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
using namespace android;
@@ -152,6 +152,21 @@
return reinterpret_cast<jlong>(new CameraMetadata());
}
+static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
+ jobject other) {
+ ALOGV("%s", __FUNCTION__);
+
+ CameraMetadata* otherMetadata =
+ CameraMetadata_getPointerThrow(env, other, "other");
+
+ // In case of exception, return
+ if (otherMetadata == NULL) return NULL;
+
+ // Clone native metadata and return new pointer
+ return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
+}
+
+
static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
ALOGV("%s", __FUNCTION__);
@@ -361,6 +376,9 @@
{ "nativeAllocate",
"()J",
(void*)CameraMetadata_allocate },
+ { "nativeAllocateCopy",
+ "(L" CAMERA_METADATA_CLASS_NAME ";)J",
+ (void *)CameraMetadata_allocateCopy },
{ "nativeIsEmpty",
"()Z",
(void*)CameraMetadata_isEmpty },
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 0cd6f4a..1c43cc5 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -190,7 +190,7 @@
int frameSize = nbChannels * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
- if (uint32_t(source) >= AUDIO_SOURCE_CNT) {
+ if ((uint32_t(source) >= AUDIO_SOURCE_CNT) && (uint32_t(source) != AUDIO_SOURCE_HOTWORD)) {
ALOGE("Error creating AudioRecord: unknown source.");
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
@@ -387,6 +387,9 @@
(jint)recorderBuffSize : sizeInBytes );
env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
+ if (readSize < 0) {
+ readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ }
return (jint) readSize;
}
@@ -427,8 +430,12 @@
}
// read new data from the recorder
- return (jint) lpRecorder->read(nativeFromJavaBuf,
+ ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
capacity < sizeInBytes ? capacity : sizeInBytes);
+ if (readSize < 0) {
+ readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ }
+ return (jint)readSize;
}
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 3fd8ed9..463be5e 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -24,6 +24,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/Log.h>
#include <binder/IServiceManager.h>
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index dd07c4f..1779c9f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -21,6 +21,7 @@
#include "utils/misc.h"
#include "cutils/debugger.h"
+#include <cutils/log.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 17a0677..c83541d 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -19,6 +19,7 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <input/Input.h>
#include "android_view_KeyEvent.h"
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index ad6c0f2..f1b90e1 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -20,6 +20,7 @@
#include <SkMatrix.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <input/Input.h>
#include "android_os_Parcel.h"
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 8b6dc60..5e29213 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -21,6 +21,7 @@
#include "android_view_PointerIcon.h"
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <android/graphics/GraphicsJNI.h>
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3f54fd7..1868469 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -26,6 +26,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
+#include <android_runtime/Log.h>
#include <binder/Parcel.h>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d4ca5a0..a194240 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2084,6 +2084,14 @@
android:description="@string/permdesc_captureAudioOutput"
android:protectionLevel="signature|system" />
+ <!-- Allows an application to capture audio for hotword detection.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
+ android:label="@string/permlab_captureAudioHotword"
+ android:description="@string/permdesc_captureAudioHotword"
+ android:protectionLevel="signature|system" />
+
<!-- Allows an application to capture video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index e591a7b..0000000
--- a/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index ea27290d..0000000
--- a/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index 7dfea4c..0000000
--- a/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 99b0279..0000000
--- a/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index f01a79e..0000000
--- a/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 7bea197..0000000
--- a/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-xxhdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index 47bc2b5..0000000
--- a/core/res/res/drawable-xxhdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-xxhdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 3bd381d..0000000
--- a/core/res/res/drawable-xxhdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/activity_picker_bg.xml b/core/res/res/drawable/activity_picker_bg.xml
deleted file mode 100644
index a471c94..0000000
--- a/core/res/res/drawable/activity_picker_bg.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_window_focused="false" android:drawable="@color/transparent" />
-
- <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
- <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
- <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
- <item android:state_focused="true" android:drawable="@drawable/activity_picker_bg_focused" />
- <item android:state_activated="true" android:drawable="@drawable/activity_picker_bg_activated" />
- <item android:drawable="@color/transparent" />
-
-</selector>
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 28c5b74..281541b 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -21,7 +21,7 @@
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:background="@android:drawable/activity_picker_bg">
+ android:background="?attr/activatedBackgroundIndicator">
<!-- Activity icon when presenting dialog
Size will be filled in by ResolverActivity -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fa6ecc8..35d0fbd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1405,6 +1405,12 @@
<string name="permdesc_captureAudioOutput">Allows the app to capture and redirect audio output.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_captureAudioHotword">Hotword detection</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_captureAudioHotword">Allows the app to capture audio for Hotword detection. The capture can
+ happen in the background but does not prevent other audio capture (e.g. Camcorder).</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_captureVideoOutput">capture video output</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_captureVideoOutput">Allows the app to capture and redirect video output.</string>
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 7e0202e..b76c8be 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -79,6 +79,8 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 463e999..a0cb1bb 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -651,19 +651,6 @@
} catch (InterruptedException e) {}
}
- /**
- * Set airplane mode
- */
- public void setAirplaneMode(Context context, boolean enableAM) {
- //set the airplane mode
- Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
- enableAM ? 1 : 0);
- // Post the intent
- Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- intent.putExtra("state", enableAM);
- context.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
-
protected static String convertToQuotedString(String string) {
return "\"" + string + "\"";
}
@@ -694,7 +681,7 @@
//A thread to set the device into airplane mode then turn on wifi.
Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() {
public void run() {
- setAirplaneMode(mContext, true);
+ mCM.setAirplaneMode(true);
connectToWifi(mPowerSsid);
}
});
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 3111489..729e1d2 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -62,7 +62,7 @@
if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON) == 1) {
log("airplane is not disabled, disable it.");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ cmActivity.mCM.setAirplaneMode(false);
}
if (!mWifiOnlyFlag) {
@@ -87,7 +87,7 @@
if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON) == 1) {
log("disable airplane mode if it is enabled");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ cmActivity.mCM.setAirplaneMode(false);
}
super.tearDown();
}
@@ -344,7 +344,7 @@
// Enable airplane mode
log("Enable airplane mode");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+ cmActivity.mCM.setAirplaneMode(true);
sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
@@ -370,7 +370,7 @@
NetworkState.DO_NOTHING, State.DISCONNECTED);
// disable airplane mode
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ cmActivity.mCM.setAirplaneMode(false);
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
@@ -400,7 +400,7 @@
assertNotNull("SSID is null", mTestAccessPoint);
// Eanble airplane mode
log("Enable airplane mode");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+ cmActivity.mCM.setAirplaneMode(true);
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
@@ -437,7 +437,7 @@
assertTrue("state validation failed", false);
}
}
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ cmActivity.mCM.setAirplaneMode(false);
}
// Test case 7: test connectivity while transit from Wifi->AM->Wifi
@@ -463,7 +463,7 @@
}
// Enable airplane mode without clearing Wifi
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+ cmActivity.mCM.setAirplaneMode(true);
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
@@ -481,7 +481,7 @@
networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED);
// Disable airplane mode
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ cmActivity.mCM.setAirplaneMode(false);
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
diff --git a/include/android_runtime/Log.h b/include/android_runtime/Log.h
new file mode 100644
index 0000000..aa6d202
--- /dev/null
+++ b/include/android_runtime/Log.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef _RUNTIME_ANDROID_LOG_H
+#define _RUNTIME_ANDROID_LOG_H
+
+// This relies on JNIHelp.h
+
+/* Logging macros.
+ *
+ * Logs an exception. If the exception is omitted or NULL, logs the current exception
+ * from the JNI environment, if any.
+ */
+#define LOG_EX(env, priority, tag, ...) \
+ jniLogException(env, ANDROID_##priority, tag, ##__VA_ARGS__)
+#define LOGV_EX(env, ...) LOG_EX(env, LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+#define LOGD_EX(env, ...) LOG_EX(env, LOG_DEBUG, LOG_TAG, ##__VA_ARGS__)
+#define LOGI_EX(env, ...) LOG_EX(env, LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define LOGW_EX(env, ...) LOG_EX(env, LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define LOGE_EX(env, ...) LOG_EX(env, LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+
+#endif // _RUNTIME_ANDROID_LOG_H
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 9aceaa9..ec5f95c 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -645,7 +645,7 @@
if (method == kCompressStored &&
((dataOffset >= cdOffset) ||
- (uncompLen >= (cdOffset - dataOffset))))
+ (uncompLen > (cdOffset - dataOffset))))
{
ALOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
(long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d1f7156..845baaf 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1532,16 +1532,6 @@
/**
* @hide
- * Checks whether speech recognition is active
- * @return true if a recording with source {@link MediaRecorder.AudioSource#VOICE_RECOGNITION}
- * is underway.
- */
- public boolean isSpeechRecognitionActive() {
- return AudioSystem.isSourceActive(MediaRecorder.AudioSource.VOICE_RECOGNITION);
- }
-
- /**
- * @hide
* Checks whether the current audio focus is exclusive.
* @return true if the top of the audio focus stack requested focus
* with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index d20f5b9..f49ef2e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -252,7 +252,8 @@
//--------------
// audio source
if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
- (audioSource > MediaRecorder.getAudioSourceMax()) ) {
+ ((audioSource > MediaRecorder.getAudioSourceMax()) &&
+ (audioSource != MediaRecorder.AudioSource.HOTWORD)) ) {
throw new IllegalArgumentException("Invalid audio source.");
}
mRecordSource = audioSource;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 949a42c..fd4c81b 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -44,9 +44,19 @@
* for encoders, readable in the output format of decoders</b></td></tr>
* <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
* <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
+ * <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
* <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr>
* <tr><td>{@link #KEY_PUSH_BLANK_BUFFERS_ON_STOP}</td><td>Integer(1)</td><td><b>video decoder rendering to a surface only</b></td></tr>
* </table>
+ * Specify both {@link #KEY_MAX_WIDTH} and {@link #KEY_MAX_HEIGHT} to enable
+ * adaptive playback (seamless resolution change) for a video decoder that
+ * supports it ({@link MediaCodecInfo.CodecCapabilities#FEATURE_AdaptivePlayback}).
+ * The values are used as hints for the codec: they are the maximum expected
+ * resolution to prepare for. Depending on codec support, preparing for larger
+ * maximum resolution may require more memory even if that resolution is never
+ * reached. These fields have no effect for codecs that do not support adaptive
+ * playback.<br /><br />
*
* Audio formats have the following keys:
* <table>
@@ -104,6 +114,20 @@
*/
public static final String KEY_HEIGHT = "height";
+ /**
+ * A key describing the maximum expected width of the content in a video
+ * decoder format, in case there are resolution changes in the video content.
+ * The associated value is an integer
+ */
+ public static final String KEY_MAX_WIDTH = "max-width";
+
+ /**
+ * A key describing the maximum expected height of the content in a video
+ * decoder format, in case there are resolution changes in the video content.
+ * The associated value is an integer
+ */
+ public static final String KEY_MAX_HEIGHT = "max-height";
+
/** A key describing the maximum size in bytes of a buffer of data
* described by this MediaFormat.
* The associated value is an integer
@@ -197,6 +221,28 @@
*/
public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
+ /**
+ * A key for boolean AUTOSELECT field. Tracks with AUTOSELECT=true are
+ * considered when automatically selecting a track without specific user
+ * choice (as defined by HLS).
+ * @hide
+ */
+ public static final String KEY_AUTOSELECT = "autoselect";
+
+ /**
+ * A key for boolean DEFAULT field. The track with DEFAULT=true is selected
+ * in the absence of a specific user choice (as defined by HLS).
+ * @hide
+ */
+ public static final String KEY_DEFAULT = "default";
+
+ /**
+ * A key for boolean FORCED field for subtitle tracks. True if it is a
+ * forced subtitle track.
+ * @hide
+ */
+ public static final String KEY_FORCED = "forced";
+
/* package private */ MediaFormat(Map<String, Object> map) {
mMap = map;
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ce1896a..bcdc1c8 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1578,7 +1578,8 @@
* unknown or could not be determined, null is returned.
*/
public MediaFormat getFormat() {
- if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
+ if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
+ || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
return mFormat;
}
return null;
@@ -1602,6 +1603,12 @@
if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
mFormat = MediaFormat.createSubtitleFormat(
MEDIA_MIMETYPE_TEXT_SUBRIP, language);
+ } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+ mFormat = MediaFormat.createSubtitleFormat(
+ MEDIA_MIMETYPE_TEXT_VTT, language);
+ mFormat.setInteger(MediaFormat.KEY_AUTOSELECT, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_DEFAULT, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_FORCED, in.readInt());
} else {
mFormat = new MediaFormat();
mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
@@ -1629,6 +1636,12 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mTrackType);
dest.writeString(getLanguage());
+
+ if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_AUTOSELECT));
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_DEFAULT));
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_FORCED));
+ }
}
/**
@@ -1693,6 +1706,12 @@
*/
public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+ /**
+ * MIME type for WebVTT subtitle data.
+ * @hide
+ */
+ public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
+
/*
* A helper function to check if the mime type is supported by media framework.
*/
@@ -1829,9 +1848,8 @@
if (i < mInbandSubtitleTracks.length) {
inbandTracks[i] = mInbandSubtitleTracks[i];
} else {
- MediaFormat format = MediaFormat.createSubtitleFormat(
- "text/vtt", tracks[i].getLanguage());
- SubtitleTrack track = mSubtitleController.addTrack(format);
+ SubtitleTrack track = mSubtitleController.addTrack(
+ tracks[i].getFormat());
inbandTracks[i] = track;
}
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 1d2b889..8dcbd6b 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -200,6 +200,19 @@
* </p>
*/
public static final int REMOTE_SUBMIX = 8;
+
+ /**
+ * Audio source for preemptible, low-priority software hotword detection
+ * It presents the same gain and pre processing tuning as {@link #VOICE_RECOGNITION}.
+ * <p>
+ * An application should use this audio source when it wishes to do
+ * always-on software hotword detection, while gracefully giving in to any other application
+ * that might want to read from the microphone.
+ * </p>
+ * This is a hidden audio source.
+ * @hide
+ */
+ protected static final int HOTWORD = 1999;
}
/**
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 666d111..bbb74d25b 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -21,6 +21,7 @@
#include "android_media_MediaDrm.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "android_os_Parcel.h"
#include "jni.h"
#include "JNIHelp.h"
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 1704d5c..1ac45d4 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -22,6 +22,7 @@
#include "android_media_Utils.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "jni.h"
#include "JNIHelp.h"
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 9b66c06..d134667 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -31,6 +31,7 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
+#include "android_runtime/Log.h"
#include "utils/Errors.h" // for status_t
#include "utils/KeyedVector.h"
#include "utils/String8.h"
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 5d27966..4e3d14e 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -25,6 +25,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
using namespace android;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index fbd5d21..77c7966 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -26,6 +26,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "MtpDatabase.h"
#include "MtpDataPacket.h"
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 113784e..b61b66c 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -28,6 +28,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "private/android_filesystem_config.h"
#include "MtpTypes.h"
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index 4982a47..d8099dd 100644
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorClasses"
#include <VideoEditorClasses.h>
#include <VideoEditorJava.h>
diff --git a/media/jni/mediaeditor/VideoEditorJava.cpp b/media/jni/mediaeditor/VideoEditorJava.cpp
index bcf9099..fde0fb5 100644
--- a/media/jni/mediaeditor/VideoEditorJava.cpp
+++ b/media/jni/mediaeditor/VideoEditorJava.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorJava"
+
#include <VideoEditorClasses.h>
#include <VideoEditorJava.h>
#include <VideoEditorLogging.h>
diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h
index 479d8b6..1f1228a 100644
--- a/media/jni/mediaeditor/VideoEditorLogging.h
+++ b/media/jni/mediaeditor/VideoEditorLogging.h
@@ -17,6 +17,16 @@
#ifndef VIDEO_EDITOR_LOGGING_H
#define VIDEO_EDITOR_LOGGING_H
+#ifndef LOG_TAG
+#error "No LOG_TAG defined!"
+#endif
+
+/*
+ * This file is used as a proxy for cutils/log.h. Include cutils/log.h here to
+ * avoid relying on import ordering.
+ */
+#include <cutils/log.h>
+
//#define VIDEOEDIT_LOGGING_ENABLED
#define VIDEOEDIT_LOG_INDENTATION (3)
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index a8c08ac..c12b1f5 100644
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorOsal"
+
#include <VideoEditorJava.h>
#include <VideoEditorLogging.h>
#include <VideoEditorOsal.h>
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index c8fb263..2f8e357 100644
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorPropertiesMain"
+
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 624bbaa..1b7faec 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -25,6 +25,7 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.os.Binder;
@@ -155,7 +156,7 @@
}
@Override
- public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
+ public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException {
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 2f271bb..56d73c0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -22,6 +22,7 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.BinderHolder;
import android.os.RemoteException;
import android.test.AndroidTestCase;
@@ -62,13 +63,13 @@
}
@Override
- public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
+ public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException {
}
}
- class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadata> {
+ class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadataNative> {
public boolean matches(Object obj) {
- return !((CameraMetadata) obj).isEmpty();
+ return !((CameraMetadataNative) obj).isEmpty();
}
}
@@ -78,20 +79,17 @@
mSurface = new Surface(mSurfaceTexture);
}
- private CaptureRequest createDefaultRequest(boolean needStream) throws Exception {
- CameraMetadata metadata = new CameraMetadata();
+ private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception {
+ CameraMetadataNative metadata = new CameraMetadataNative();
assertTrue(metadata.isEmpty());
- CaptureRequest request = new CaptureRequest();
- assertTrue(request.isEmpty());
-
int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
assertFalse(metadata.isEmpty());
- request.swap(metadata);
+ CaptureRequest.Builder request = new CaptureRequest.Builder(metadata);
assertFalse(request.isEmpty());
- assertTrue(metadata.isEmpty());
+ assertFalse(metadata.isEmpty());
if (needStream) {
int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20,
/* ignored */30, mSurface);
@@ -150,14 +148,13 @@
@SmallTest
public void testCreateDefaultRequest() throws Exception {
- CameraMetadata metadata = new CameraMetadata();
+ CameraMetadataNative metadata = new CameraMetadataNative();
assertTrue(metadata.isEmpty());
int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
assertFalse(metadata.isEmpty());
- metadata.close();
}
@SmallTest
@@ -208,37 +205,39 @@
@SmallTest
public void testSubmitBadRequest() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */false);
- int status = mCameraUser.submitRequest(request, /* streaming */false);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
+ CaptureRequest request1 = builder.build();
+ int status = mCameraUser.submitRequest(request1, /* streaming */false);
assertEquals("Expected submitRequest to return BAD_VALUE " +
"since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
- request.addTarget(mSurface);
- status = mCameraUser.submitRequest(request, /* streaming */false);
+ builder.addTarget(mSurface);
+ CaptureRequest request2 = builder.build();
+ status = mCameraUser.submitRequest(request2, /* streaming */false);
assertEquals("Expected submitRequest to return BAD_VALUE since " +
"the target surface wasn't registered with createStream.",
CameraBinderTestUtils.BAD_VALUE, status);
-
- request.close();
}
@SmallTest
public void testSubmitGoodRequest() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+ CaptureRequest request = builder.build();
// Submit valid request twice.
int requestId1 = submitCameraRequest(request, /* streaming */false);
int requestId2 = submitCameraRequest(request, /* streaming */false);
assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2);
- request.close();
}
@SmallTest
public void testSubmitStreamingRequest() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+
+ CaptureRequest request = builder.build();
// Submit valid request once (non-streaming), and another time
// (streaming)
@@ -260,12 +259,11 @@
assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
status);
- request.close();
}
@SmallTest
public void testCameraInfo() throws RemoteException {
- CameraMetadata info = new CameraMetadata();
+ CameraMetadataNative info = new CameraMetadataNative();
int status = mCameraUser.getCameraInfo(/*out*/info);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
@@ -276,8 +274,8 @@
@SmallTest
public void testWaitUntilIdle() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */true);
- int requestIdStreaming = submitCameraRequest(request, /* streaming */true);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+ int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
// Test Bad case first: waitUntilIdle when there is active repeating request
int status = mCameraUser.waitUntilIdle();
@@ -294,7 +292,7 @@
@SmallTest
public void testCaptureResultCallbacks() throws Exception {
IsMetadataNotEmpty matcher = new IsMetadataNotEmpty();
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Test both single request and streaming request.
int requestId1 = submitCameraRequest(request, /* streaming */false);
@@ -307,7 +305,6 @@
.onResultReceived(
eq(streamingId),
argThat(matcher));
- request.close();
}
@SmallTest
@@ -319,7 +316,7 @@
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
// Then set up a stream
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Flush should still be a no-op, really
status = mCameraUser.flush();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index ecf01d9..874e078 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -23,8 +23,9 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.Rational;
import android.hardware.camera2.Size;
+import android.hardware.camera2.impl.CameraMetadataNative;
-import static android.hardware.camera2.CameraMetadata.*;
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
@@ -42,7 +43,7 @@
*/
public class CameraMetadataTest extends junit.framework.TestCase {
- CameraMetadata mMetadata;
+ CameraMetadataNative mMetadata;
Parcel mParcel;
// Sections
@@ -62,13 +63,12 @@
@Override
public void setUp() {
- mMetadata = new CameraMetadata();
+ mMetadata = new CameraMetadataNative();
mParcel = Parcel.obtain();
}
@Override
public void tearDown() throws Exception {
- mMetadata.close();
mMetadata = null;
mParcel.recycle();
@@ -82,115 +82,47 @@
}
@SmallTest
- public void testClose() throws Exception {
- mMetadata.isEmpty(); // no throw
-
- assertFalse(mMetadata.isClosed());
-
- mMetadata.close();
-
- assertTrue(mMetadata.isClosed());
-
- // OK: second close should not throw
- mMetadata.close();
-
- assertTrue(mMetadata.isClosed());
-
- // All other calls after close should throw IllegalStateException
-
- try {
- mMetadata.isEmpty();
- fail("Unreachable -- isEmpty after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.getEntryCount();
- fail("Unreachable -- getEntryCount after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
-
- try {
- mMetadata.swap(mMetadata);
- fail("Unreachable -- swap after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.readFromParcel(mParcel);
- fail("Unreachable -- readFromParcel after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.writeToParcel(mParcel, /*flags*/0);
- fail("Unreachable -- writeToParcel after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.readValues(/*tag*/0);
- fail("Unreachable -- readValues after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.writeValues(/*tag*/0, /*source*/new byte[] { 1,2,3 });
- fail("Unreachable -- readValues after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
- }
-
- @SmallTest
public void testGetTagFromKey() {
// Test success
assertEquals(ANDROID_COLOR_CORRECTION_MODE,
- CameraMetadata.getTag("android.colorCorrection.mode"));
+ CameraMetadataNative.getTag("android.colorCorrection.mode"));
assertEquals(ANDROID_COLOR_CORRECTION_TRANSFORM,
- CameraMetadata.getTag("android.colorCorrection.transform"));
+ CameraMetadataNative.getTag("android.colorCorrection.transform"));
assertEquals(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
- CameraMetadata.getTag("android.control.aeAntibandingMode"));
+ CameraMetadataNative.getTag("android.control.aeAntibandingMode"));
assertEquals(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
- CameraMetadata.getTag("android.control.aeExposureCompensation"));
+ CameraMetadataNative.getTag("android.control.aeExposureCompensation"));
// Test failures
try {
- CameraMetadata.getTag(null);
+ CameraMetadataNative.getTag(null);
fail("A null key should throw NPE");
} catch(NullPointerException e) {
}
try {
- CameraMetadata.getTag("android.control");
+ CameraMetadataNative.getTag("android.control");
fail("A section name only should not be a valid key");
} catch(IllegalArgumentException e) {
}
try {
- CameraMetadata.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
+ CameraMetadataNative.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
fail("A valid section with an invalid tag name should not be a valid key");
} catch(IllegalArgumentException e) {
}
try {
- CameraMetadata.getTag("android");
+ CameraMetadataNative.getTag("android");
fail("A namespace name only should not be a valid key");
} catch(IllegalArgumentException e) {
}
try {
- CameraMetadata.getTag("this.key.is.definitely.invalid");
+ CameraMetadataNative.getTag("this.key.is.definitely.invalid");
fail("A completely fake key name should not be valid");
} catch(IllegalArgumentException e) {
}
@@ -198,14 +130,14 @@
@SmallTest
public void testGetTypeFromTag() {
- assertEquals(TYPE_BYTE, CameraMetadata.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
- assertEquals(TYPE_FLOAT, CameraMetadata.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
- assertEquals(TYPE_BYTE, CameraMetadata.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
+ assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
+ assertEquals(TYPE_FLOAT, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
+ assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
assertEquals(TYPE_INT32,
- CameraMetadata.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
+ CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
try {
- CameraMetadata.getNativeType(0xDEADF00D);
+ CameraMetadataNative.getNativeType(0xDEADF00D);
fail("No type should exist for invalid tag 0xDEADF00D");
} catch(IllegalArgumentException e) {
}
@@ -454,7 +386,7 @@
@SmallTest
public void testReadWriteEnumWithCustomValues() {
- CameraMetadata.registerEnumValues(AeAntibandingMode.class, new int[] {
+ CameraMetadataNative.registerEnumValues(AeAntibandingMode.class, new int[] {
0,
10,
20,
@@ -475,7 +407,7 @@
Key<AeAntibandingMode[]> aeAntibandingModeKey =
new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
AeAntibandingMode[].class);
- byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadata
+ byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
.getTag("android.control.aeAvailableAntibandingModes"));
byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
assertArrayEquals(expectedValues, aeAntibandingModeValues);
@@ -485,7 +417,7 @@
* Stranger cases that don't use byte enums
*/
// int (n)
- CameraMetadata.registerEnumValues(AvailableFormat.class, new int[] {
+ CameraMetadataNative.registerEnumValues(AvailableFormat.class, new int[] {
0x20,
0x32315659,
0x11,
@@ -505,7 +437,7 @@
Key<AeAntibandingMode> availableFormatsKey =
new Key<AeAntibandingMode>("android.scaler.availableFormats",
AeAntibandingMode.class);
- byte[] availableFormatValues = mMetadata.readValues(CameraMetadata
+ byte[] availableFormatValues = mMetadata.readValues(CameraMetadataNative
.getTag(availableFormatsKey.getName()));
int[] expectedIntValues = new int[] {
diff --git a/services/jni/com_android_server_AssetAtlasService.cpp b/services/jni/com_android_server_AssetAtlasService.cpp
index 62e950f..885d21e 100644
--- a/services/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/jni/com_android_server_AssetAtlasService.cpp
@@ -20,6 +20,7 @@
#include "JNIHelp.h"
#include <android_view_GraphicBuffer.h>
+#include <cutils/log.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/jni/com_android_server_UsbDeviceManager.cpp
index 0014db5..3551733 100644
--- a/services/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/jni/com_android_server_UsbDeviceManager.cpp
@@ -20,6 +20,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include <stdio.h>
#include <asm/byteorder.h>
diff --git a/services/jni/com_android_server_UsbHostManager.cpp b/services/jni/com_android_server_UsbHostManager.cpp
index d0a6cdf..639790b7 100644
--- a/services/jni/com_android_server_UsbHostManager.cpp
+++ b/services/jni/com_android_server_UsbHostManager.cpp
@@ -20,6 +20,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "utils/Vector.h"
#include <usbhost/usbhost.h>
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index d8b8b94..4ab2086 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -29,6 +29,7 @@
#include "jni.h"
#include <limits.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <utils/Looper.h>
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
index a187521..ac269eb 100644
--- a/services/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -23,6 +23,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "hardware/fused_location.h"
#include "hardware_legacy/power.h"
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 98de12a..aec254b 100644
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -26,6 +26,7 @@
#include "utils/Log.h"
#include "utils/misc.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include <string.h>
#include <pthread.h>
diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/jni/com_android_server_power_PowerManagerService.cpp
index 88b13b5..151e134 100644
--- a/services/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/jni/com_android_server_power_PowerManagerService.cpp
@@ -26,6 +26,7 @@
#include <limits.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Timers.h>
#include <utils/misc.h>
#include <utils/String8.h>