Merge "camera3: Add flush"
diff --git a/include/hardware/audio.h b/include/hardware/audio.h
index 3a0962e..b0c0c0e 100644
--- a/include/hardware/audio.h
+++ b/include/hardware/audio.h
@@ -67,6 +67,7 @@
 #define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp"
 #define AUDIO_HARDWARE_MODULE_ID_USB "usb"
 #define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix"
+#define AUDIO_HARDWARE_MODULE_ID_CODEC_OFFLOAD "codec_offload"
 
 /**************************************/
 
@@ -117,16 +118,35 @@
  * "sup_sampling_rates=44100|48000" */
 #define AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES "sup_sampling_rates"
 
+/**
+ * audio codec parameters
+ */
+
+#define AUDIO_OFFLOAD_CODEC_PARAMS "music_offload_codec_param"
+#define AUDIO_OFFLOAD_CODEC_BIT_PER_SAMPLE "music_offload_bit_per_sample"
+#define AUDIO_OFFLOAD_CODEC_BIT_RATE "music_offload_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE "music_offload_avg_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_ID "music_offload_codec_id"
+#define AUDIO_OFFLOAD_CODEC_BLOCK_ALIGN "music_offload_block_align"
+#define AUDIO_OFFLOAD_CODEC_SAMPLE_RATE "music_offload_sample_rate"
+#define AUDIO_OFFLOAD_CODEC_ENCODE_OPTION "music_offload_encode_option"
+#define AUDIO_OFFLOAD_CODEC_NUM_CHANNEL  "music_offload_num_channels"
+#define AUDIO_OFFLOAD_CODEC_DOWN_SAMPLING  "music_offload_down_sampling"
+#define AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES  "delay_samples"
+#define AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES  "padding_samples"
 
 /**************************************/
 
-/* common audio stream configuration parameters */
+/* common audio stream configuration parameters
+ * You should memset() the entire structure to zero before use to
+ * ensure forward compatibility
+ */
 struct audio_config {
     uint32_t sample_rate;
     audio_channel_mask_t channel_mask;
     audio_format_t  format;
+    audio_offload_info_t offload_info;
 };
-
 typedef struct audio_config audio_config_t;
 
 /* common audio stream parameters and operations */
@@ -213,6 +233,22 @@
 };
 typedef struct audio_stream audio_stream_t;
 
+/* type of asynchronous write callback events. Mutually exclusive */
+typedef enum {
+    STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
+    STREAM_CBK_EVENT_DRAIN_READY  /* drain completed */
+} stream_callback_event_t;
+
+typedef int (*stream_callback_t)(stream_callback_event_t event, void *param, void *cookie);
+
+/* type of drain requested to audio_stream_out->drain(). Mutually exclusive */
+typedef enum {
+    AUDIO_DRAIN_ALL,            /* drain() returns when all data has been played */
+    AUDIO_DRAIN_EARLY_NOTIFY    /* drain() returns a short time before all data
+                                   from the current track has been played to
+                                   give time for gapless track switch */
+} audio_drain_type_t;
+
 /**
  * audio_stream_out is the abstraction interface for the audio output hardware.
  *
@@ -242,6 +278,13 @@
      * negative status_t. If at least one frame was written successfully prior to the error,
      * it is suggested that the driver return that successful (short) byte count
      * and then return an error in the subsequent call.
+     *
+     * If set_callback() has previously been called to enable non-blocking mode
+     * the write() is not allowed to block. It must write only the number of
+     * bytes that currently fit in the driver/hardware buffer and then return
+     * this byte count. If this is less than the requested write size the
+     * callback function must be called when more space is available in the
+     * driver/hardware buffer.
      */
     ssize_t (*write)(struct audio_stream_out *stream, const void* buffer,
                      size_t bytes);
@@ -259,6 +302,60 @@
     int (*get_next_write_timestamp)(const struct audio_stream_out *stream,
                                     int64_t *timestamp);
 
+    /**
+     * set the callback function for notifying completion of non-blocking
+     * write and drain.
+     * Calling this function implies that all future write() and drain()
+     * must be non-blocking and use the callback to signal completion.
+     */
+    int (*set_callback)(struct audio_stream_out *stream,
+            stream_callback_t callback, void *cookie);
+
+    /**
+     * Notifies to the audio driver to stop playback however the queued buffers are
+     * retained by the hardware. Useful for implementing pause/resume. Empty implementation
+     * if not supported however should be implemented for hardware with non-trivial
+     * latency. In the pause state audio hardware could still be using power. User may
+     * consider calling suspend after a timeout.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     */
+    int (*pause)(struct audio_stream_out* stream);
+
+    /**
+     * Notifies to the audio driver to resume playback following a pause.
+     * Returns error if called without matching pause.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     */
+    int (*resume)(struct audio_stream_out* stream);
+
+    /**
+     * Requests notification when data buffered by the driver/hardware has
+     * been played. If set_callback() has previously been called to enable
+     * non-blocking mode, the drain() must not block, instead it should return
+     * quickly and completion of the drain is notified through the callback.
+     * If set_callback() has not been called, the drain() must block until
+     * completion.
+     * If type==AUDIO_DRAIN_ALL, the drain completes when all previously written
+     * data has been played.
+     * If type==AUDIO_DRAIN_EARLY_NOTIFY, the drain completes shortly before all
+     * data for the current track has played to allow time for the framework
+     * to perform a gapless track switch.
+     *
+     * Drain must return immediately on stop() and flush() call
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     */
+    int (*drain)(struct audio_stream_out* stream, audio_drain_type_t type );
+
+    /**
+     * Notifies to the audio driver to flush the queued data. Stream must already
+     * be paused before calling flush().
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     */
+   int (*flush)(struct audio_stream_out* stream);
 };
 typedef struct audio_stream_out audio_stream_out_t;
 
@@ -296,18 +393,14 @@
 static inline size_t audio_stream_frame_size(const struct audio_stream *s)
 {
     size_t chan_samp_sz;
+    audio_format_t format = s->get_format(s);
 
-    switch (s->get_format(s)) {
-    case AUDIO_FORMAT_PCM_16_BIT:
-        chan_samp_sz = sizeof(int16_t);
-        break;
-    case AUDIO_FORMAT_PCM_8_BIT:
-    default:
-        chan_samp_sz = sizeof(int8_t);
-        break;
+    if (audio_is_linear_pcm(format)) {
+        chan_samp_sz = audio_bytes_per_sample(format);
+        return popcount(s->get_channels(s)) * chan_samp_sz;
     }
 
-    return popcount(s->get_channels(s)) * chan_samp_sz;
+    return sizeof(int8_t);
 }
 
 
diff --git a/include/hardware/audio_policy.h b/include/hardware/audio_policy.h
index c635ebf..4e75e02 100644
--- a/include/hardware/audio_policy.h
+++ b/include/hardware/audio_policy.h
@@ -133,7 +133,8 @@
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
-                                    audio_output_flags_t flags);
+                                    audio_output_flags_t flags,
+                                    const audio_offload_info_t *offloadInfo);
 
     /* indicates to the audio policy manager that the output starts being used
      * by corresponding stream. */
@@ -241,6 +242,10 @@
 
     /* dump state */
     int (*dump)(const struct audio_policy *pol, int fd);
+
+    /* check if offload is possible for given sample rate, bitrate, duration, ... */
+    bool (*is_offload_supported)(const struct audio_policy *pol,
+                                const audio_offload_info_t *info);
 };
 
 /* audio hw module handle used by load_hw_module(), open_output_on_module()
@@ -390,7 +395,8 @@
                                      audio_format_t *pFormat,
                                      audio_channel_mask_t *pChannelMask,
                                      uint32_t *pLatencyMs,
-                                     audio_output_flags_t flags);
+                                     audio_output_flags_t flags,
+                                     const audio_offload_info_t *offloadInfo);
 
     /* Opens an audio input on a particular HW module.
      *
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
index 2741332..c00a8f7 100755
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -451,6 +451,8 @@
     /* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End */
     int (*le_test_mode)(uint16_t opcode, uint8_t *buf, uint8_t len);
 
+    /* enable or disable bluetooth HCI snoop log */
+    int (*config_hci_snoop_log)(uint8_t enable);
 } bt_interface_t;
 
 /** TODO: Need to add APIs for Service Discovery, Service authorization and
diff --git a/include/hardware/fused_location.h b/include/hardware/fused_location.h
index f61575d..fecf822 100644
--- a/include/hardware/fused_location.h
+++ b/include/hardware/fused_location.h
@@ -49,7 +49,7 @@
 /**
  * Name for the FLP location interface
  */
-#define FLP_DEBUG_INTERFACE     "flp_debug"
+#define FLP_DIAGNOSTIC_INTERFACE     "flp_diagnostic"
 
 /**
  * Name for the FLP_Geofencing interface.
@@ -57,6 +57,11 @@
 #define FLP_GEOFENCING_INTERFACE   "flp_geofencing"
 
 /**
+ * Name for the FLP_device context interface.
+ */
+#define FLP_DEVICE_CONTEXT_INTERFACE   "flp_device_context"
+
+/**
  * Constants to indicate the various subsystems
  * that will be used.
  */
@@ -84,6 +89,8 @@
  * fix has been obtained. This flag controls that option.
  * Its the responsibility of the upper layers (caller) to switch
  * it off, if it knows that the AP might go to sleep.
+ * When this bit is on amidst a batching session, batching should
+ * continue while location fixes are reported in real time.
  */
 #define FLP_BATCH_CALLBACK_ON_LOCATION_FIX   0x0000002
 
@@ -149,7 +156,7 @@
 
 /**
  *  Callback with location information.
- *  Can only be called from a thread created by create_thread_cb.
+ *  Can only be called from a thread associated to JVM using set_thread_event_cb.
  *  Parameters:
  *     num_locations is the number of batched locations available.
  *     location is the pointer to an array of pointers to location objects.
@@ -168,10 +175,13 @@
 typedef void (*flp_release_wakelock)();
 
 /**
- * Callback for creating a thread that can call into the Java framework code.
- * This must be used to create any threads that report events up to the framework.
+ * Callback for associating a thread that can call into the Java framework code.
+ * This must be used to initialize any threads that report events up to the framework.
+ * Return value:
+ *      FLP_RESULT_SUCCESS on success.
+ *      FLP_RESULT_ERROR if the association failed in the current thread.
  */
-typedef pthread_t (*flp_create_thread)(ThreadEvent event);
+typedef int (*flp_set_thread_event)(ThreadEvent event);
 
 /** FLP callback structure. */
 typedef struct {
@@ -180,7 +190,7 @@
     flp_location_callback location_cb;
     flp_acquire_wakelock acquire_wakelock_cb;
     flp_release_wakelock release_wakelock_cb;
-    flp_create_thread create_thread_cb;
+    flp_set_thread_event set_thread_event_cb;
 } FlpCallbacks;
 
 
@@ -189,6 +199,8 @@
     /**
      * Maximum power in mW that the underlying implementation
      * can use for this batching call.
+     * If max_power_allocation_mW is 0, only fixes that are generated
+     * at no additional cost of power shall be reported.
      */
     double max_power_allocation_mW;
 
@@ -203,7 +215,9 @@
      * FLP_BATCH_CALLBACK_ON_LOCATION_FIX - If set the location
      * callback will be called every time there is a location fix.
      * Its the responsibility of the upper layers (caller) to switch
-     * it off, if it knows that the AP might go to sleep.
+     * it off, if it knows that the AP might go to sleep. When this
+     * bit is on amidst a batching session, batching should continue
+     * while location fixes are reported in real time.
      *
      * Other flags to be bitwised ORed in the future.
      */
@@ -240,7 +254,10 @@
     int (*init)(FlpCallbacks* callbacks );
 
     /**
-     * Return the batch size (in bytes) available in the hardware.
+     * Return the batch size (in number of FlpLocation objects)
+     * available in the hardware.  Note, different HW implementations
+     * may have different sample sizes.  This shall return number
+     * of samples defined in the format of FlpLocation.
      * This will be used by the upper layer, to decide on the batching
      * interval and whether the AP should be woken up or not.
      */
@@ -341,32 +358,74 @@
 };
 
 /**
- * FLP debug callback structure.
+ * Callback for reports diagnostic data into the Java framework code.
+*/
+typedef void (*report_data)(char* data, int length);
+
+/**
+ * FLP diagnostic callback structure.
  * Currently, not used - but this for future extension.
  */
 typedef struct {
-    /** set to sizeof(FlpDebugCallbacks) */
+    /** set to sizeof(FlpDiagnosticCallbacks) */
     size_t      size;
-    flp_create_thread create_thread_cb;
-} FlpDebugCallbacks;
 
-/** Extended interface for debug support. */
+    flp_set_thread_event set_thread_event_cb;
+
+    /** reports diagnostic data into the Java framework code */
+    report_data data_cb;
+} FlpDiagnosticCallbacks;
+
+/** Extended interface for diagnostic support. */
 typedef struct {
-    /** set to sizeof(FlpDebugInterface) */
+    /** set to sizeof(FlpDiagnosticInterface) */
     size_t          size;
 
     /**
-     * Opens the debug interface and provides the callback routines
+     * Opens the diagnostic interface and provides the callback routines
      * to the implemenation of this interface.
      */
-    void  (*init)(FlpDebugCallbacks* callbacks);
+    void  (*init)(FlpDiagnosticCallbacks* callbacks);
+
+    /**
+     * Injects diagnostic data into the FLP subsystem.
+     * Return 0 on success, -1 on error.
+     **/
+    int  (*inject_data)(char* data, int length );
+} FlpDiagnosticInterface;
+
+/**
+ * Context setting information.
+ * All these settings shall be injected to FLP HAL at FLP init time.
+ * Following that, only the changed setting need to be re-injected
+ * upon changes.
+ */
+
+#define FLP_DEVICE_CONTEXT_GPS_ENABLED                     (1U<<0)
+#define FLP_DEVICE_CONTEXT_AGPS_ENABLED                    (1U<<1)
+#define FLP_DEVICE_CONTEXT_NETWORK_POSITIONING_ENABLED     (1U<<2)
+#define FLP_DEVICE_CONTEXT_WIFI_CONNECTIVITY_ENABLED       (1U<<3)
+#define FLP_DEVICE_CONTEXT_WIFI_POSITIONING_ENABLED        (1U<<4)
+#define FIP_DEVICE_CONTEXT_HW_NETWORK_POSITIONING ENABLED  (1U<<5)
+#define FLP_DEVICE_CONTEXT_AIRPLANE_MODE_ON                (1U<<6)
+#define FLP_DEVICE_CONTEXT_DATA_ENABLED                    (1U<<7)
+#define FLP_DEVICE_CONTEXT_ROAMING_ENABLED                 (1U<<8)
+#define FLP_DEVICE_CONTEXT_CURRENTLY_ROAMING               (1U<<9)
+#define FLP_DEVICE_CONTEXT_SENSOR_ENABLED                  (1U<<10)
+#define FLP_DEVICE_CONTEXT_BLUETOOTH_ENABLED               (1U<<11)
+#define FLP_DEVICE_CONTEXT_CHARGER_ON                      (1U<<12)
+
+/** Extended interface for device context support. */
+typedef struct {
+    /** set to sizeof(FlpDeviceContextInterface) */
+    size_t          size;
 
     /**
      * Injects debug data into the FLP subsystem.
      * Return 0 on success, -1 on error.
      **/
-    int  (*inject_debug_data)(char* data, int length );
-} FlpDebugInterface;
+    int  (*inject_device_context)(uint32_t enabledMask);
+} FlpDeviceContextInterface;
 
 
 /**
@@ -449,7 +508,7 @@
  *      location    - The current location as determined by the FLP subsystem.
  *      transition  - Can be one of FLP_GEOFENCE_TRANSITION_ENTERED, FLP_GEOFENCE_TRANSITION_EXITED,
  *                    FLP_GEOFENCE_TRANSITION_UNCERTAIN.
- *      timestamp   - Timestamp when the transition was detected.
+ *      timestamp   - Timestamp when the transition was detected; -1 if not available.
  *      sources_used - Bitwise OR of FLP_TECH_MASK flags indicating which
  *                     subsystems were used.
  *
@@ -530,13 +589,15 @@
 typedef void (*flp_geofence_resume_callback) (int32_t geofence_id, int32_t result);
 
 typedef struct {
+    /** set to sizeof(FlpGeofenceCallbacks) */
+    size_t size;
     flp_geofence_transition_callback geofence_transition_callback;
     flp_geofence_monitor_status_callback geofence_status_callback;
     flp_geofence_add_callback geofence_add_callback;
     flp_geofence_remove_callback geofence_remove_callback;
     flp_geofence_pause_callback geofence_pause_callback;
     flp_geofence_resume_callback geofence_resume_callback;
-    flp_create_thread create_thread_cb;
+    flp_set_thread_event set_thread_event_cb;
 } FlpGeofenceCallbacks;
 
 
@@ -649,6 +710,15 @@
    void (*resume_geofence) (int32_t geofence_id, int monitor_transitions);
 
    /**
+    * Modify a particular geofence option.
+    * Parameters:
+    *    geofence_id - The id for the geofence.
+    *    options - Various options associated with the geofence. See
+    *        GeofenceOptions structure for details.
+    */
+   void (*modify_geofence_option) (int32_t geofence_id, GeofenceOptions* options);
+
+   /**
     * Remove a list of geofences. After the function returns, no notifications
     * should be sent.
     * Parameter:
diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h
index 9c62242..0dbebcf 100644
--- a/include/hardware/gralloc.h
+++ b/include/hardware/gralloc.h
@@ -104,6 +104,9 @@
     /* mask for the software usage bit-mask */
     GRALLOC_USAGE_HW_MASK               = 0x00071F00,
 
+    /* buffer will be used as a RenderScript Allocation */
+    GRALLOC_USAGE_RENDERSCRIPT          = 0x00100000,
+
     /* buffer should be displayed full-screen on an external display when
      * possible
      */
diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h
index d75a047..9492d3a 100644
--- a/include/hardware/hwcomposer.h
+++ b/include/hardware/hwcomposer.h
@@ -54,6 +54,13 @@
     int bottom;
 } hwc_rect_t;
 
+typedef struct hwc_frect {
+    float left;
+    float top;
+    float right;
+    float bottom;
+} hwc_frect_t;
+
 typedef struct hwc_region {
     size_t numRects;
     hwc_rect_t const* rects;
@@ -149,8 +156,17 @@
             int32_t blending;
 
             /* area of the source to consider, the origin is the top-left corner of
-             * the buffer */
-            hwc_rect_t sourceCrop;
+             * the buffer. As of HWC_DEVICE_API_VERSION_1_3, sourceRect uses floats.
+             * If the h/w can't support a non-integer source crop rectangle, it should
+             * punt to OpenGL ES composition.
+             */
+            union {
+                // crop rectangle in integer (pre HWC_DEVICE_API_VERSION_1_3)
+                hwc_rect_t sourceCropi;
+                hwc_rect_t sourceCrop; // just for source compatibility
+                // crop rectangle in floats (as of HWC_DEVICE_API_VERSION_1_3)
+                hwc_frect_t sourceCropf;
+            };
 
             /* where to composite the sourceCrop onto the display. The sourceCrop
              * is scaled using linear filtering to the displayFrame. The origin is the
diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h
index 1edfd3d..ce4723c 100644
--- a/include/hardware/hwcomposer_defs.h
+++ b/include/hardware/hwcomposer_defs.h
@@ -35,6 +35,7 @@
 #define HWC_DEVICE_API_VERSION_1_0  HARDWARE_DEVICE_API_VERSION_2(1, 0, HWC_HEADER_VERSION)
 #define HWC_DEVICE_API_VERSION_1_1  HARDWARE_DEVICE_API_VERSION_2(1, 1, HWC_HEADER_VERSION)
 #define HWC_DEVICE_API_VERSION_1_2  HARDWARE_DEVICE_API_VERSION_2(1, 2, HWC_HEADER_VERSION)
+#define HWC_DEVICE_API_VERSION_1_3  HARDWARE_DEVICE_API_VERSION_2(1, 3, HWC_HEADER_VERSION)
 
 enum {
     /* hwc_composer_device_t::set failed in EGL */
diff --git a/include/hardware/power.h b/include/hardware/power.h
index 6c55061..89d57ed 100644
--- a/include/hardware/power.h
+++ b/include/hardware/power.h
@@ -28,7 +28,6 @@
 #define POWER_MODULE_API_VERSION_0_1  HARDWARE_MODULE_API_VERSION(0, 1)
 #define POWER_MODULE_API_VERSION_0_2  HARDWARE_MODULE_API_VERSION(0, 2)
 
-
 /**
  * The id of this module
  */
@@ -41,6 +40,11 @@
 typedef enum {
     POWER_HINT_VSYNC = 0x00000001,
     POWER_HINT_INTERACTION = 0x00000002,
+    /* DO NOT USE POWER_HINT_VIDEO_ENCODE/_DECODE!  They will be removed in
+     * KLP.
+     */
+    POWER_HINT_VIDEO_ENCODE = 0x00000003,
+    POWER_HINT_VIDEO_DECODE = 0x00000004
 } power_hint_t;
 
 /**
diff --git a/include/hardware/sensors.h b/include/hardware/sensors.h
index 7778e8f..b377051 100644
--- a/include/hardware/sensors.h
+++ b/include/hardware/sensors.h
@@ -451,6 +451,9 @@
  *  SENSOR_TYPE_MAGNETIC_FIELD must be present and both must return the
  *  same sensor_t::name and sensor_t::vendor.
  *
+ *  Minimum filtering should be applied to this sensor. In particular, low pass
+ *  filters should be avoided.
+ *
  * See SENSOR_TYPE_MAGNETIC_FIELD for more information
  */
 #define SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED     (14)
@@ -608,7 +611,7 @@
  *
  * A sensor of this type returns the number of steps taken by the user since
  * the last reboot while activated. The value is returned as a uint64_t and is
- * reset to zero only on a system reboot.
+ * reset to zero only on a system / android reboot.
  *
  * The timestamp of the event is set to the time when the first step
  * for that event was taken.
@@ -662,7 +665,9 @@
  *  of using a gyroscope.
  *
  *  This sensor must be based on a magnetometer. It cannot be implemented using
- *  a gyroscope, and gyroscope input cannot be used by this sensor.
+ *  a gyroscope, and gyroscope input cannot be used by this sensor, as the
+ *  goal of this sensor is to be low power.
+ *  The accelerometer can be (and usually is) used.
  *
  *  Just like SENSOR_TYPE_ROTATION_VECTOR, this sensor reports an estimated
  *  heading accuracy:
@@ -761,45 +766,51 @@
     int64_t timestamp;
 
     union {
-        float           data[16];
+        union {
+            float           data[16];
 
-        /* acceleration values are in meter per second per second (m/s^2) */
-        sensors_vec_t   acceleration;
+            /* acceleration values are in meter per second per second (m/s^2) */
+            sensors_vec_t   acceleration;
 
-        /* magnetic vector values are in micro-Tesla (uT) */
-        sensors_vec_t   magnetic;
+            /* magnetic vector values are in micro-Tesla (uT) */
+            sensors_vec_t   magnetic;
 
-        /* orientation values are in degrees */
-        sensors_vec_t   orientation;
+            /* orientation values are in degrees */
+            sensors_vec_t   orientation;
 
-        /* gyroscope values are in rad/s */
-        sensors_vec_t   gyro;
+            /* gyroscope values are in rad/s */
+            sensors_vec_t   gyro;
 
-        /* temperature is in degrees centigrade (Celsius) */
-        float           temperature;
+            /* temperature is in degrees centigrade (Celsius) */
+            float           temperature;
 
-        /* distance in centimeters */
-        float           distance;
+            /* distance in centimeters */
+            float           distance;
 
-        /* light in SI lux units */
-        float           light;
+            /* light in SI lux units */
+            float           light;
 
-        /* pressure in hectopascal (hPa) */
-        float           pressure;
+            /* pressure in hectopascal (hPa) */
+            float           pressure;
 
-        /* relative humidity in percent */
-        float           relative_humidity;
+            /* relative humidity in percent */
+            float           relative_humidity;
 
-        /* step-counter */
-        uint64_t        step_counter;
+            /* uncalibrated gyroscope values are in rad/s */
+            uncalibrated_event_t uncalibrated_gyro;
 
-        /* uncalibrated gyroscope values are in rad/s */
-        uncalibrated_event_t uncalibrated_gyro;
+            /* uncalibrated magnetometer values are in micro-Teslas */
+            uncalibrated_event_t uncalibrated_magnetic;
+        };
 
-        /* uncalibrated magnetometer values are in micro-Teslas */
-        uncalibrated_event_t uncalibrated_magnetic;
+        union {
+            uint64_t        data[8];
+
+            /* step-counter */
+            uint64_t        step_counter;
+        } u64;
     };
-    uint32_t        reserved1[4];
+    uint32_t reserved1[4];
 } sensors_event_t;
 
 
@@ -903,6 +914,10 @@
              * handle is the handle of the sensor to change.
              * enabled set to 1 to enable, or 0 to disable the sensor.
              *
+             * if enabled is set to 1, the sensor is activated even if
+             * setDelay() wasn't called before. In this case, a default rate
+             * should be used.
+             *
              * unless otherwise noted in the sensor types definitions, an
              * activated sensor never prevents the SoC to go into suspend
              * mode; that is, the HAL shall not hold a partial wake-lock on
@@ -912,10 +927,10 @@
              * receiving an event and they must still accept to be deactivated
              * through a call to activate(..., ..., 0).
              *
-             * if "enabled" is true and the sensor is already activated, this
+             * if "enabled" is 1 and the sensor is already activated, this
              * function is a no-op and succeeds.
              *
-             * if "enabled" is false and the sensor is already de-activated,
+             * if "enabled" is 0 and the sensor is already de-activated,
              * this function is a no-op and succeeds.
              *
              * return 0 on success, negative errno code otherwise
@@ -939,6 +954,9 @@
              * sensor_t::minDelay unless sensor_t::minDelay is 0, in which
              * case it is clamped to >= 1ms.
              *
+             * setDelay will not be called when the sensor is in batching mode.
+             * In this case, batch() will be called with the new period.
+             *
              * @return 0 if successful, < 0 on error
              */
             int (*setDelay)(struct sensors_poll_device_t *dev,
@@ -1068,19 +1086,30 @@
      * if a batch call with SENSORS_BATCH_DRY_RUN is successful,
      * the same call without SENSORS_BATCH_DRY_RUN must succeed as well).
      *
-     * If successful, 0 is returned.
-     * If the specified sensor doesn't support batch mode, -EINVAL is returned.
-     * If the specified sensor's trigger-mode is one-shot, -EINVAL is returned.
-     * If WAKE_UPON_FIFO_FULL is specified and the specified sensor's internal
-     * FIFO is too small to store at least 10 seconds worth of data at the
-     * given rate, -EINVAL is returned. Note that as stated above, this has to
-     * be determined at compile time, and not based on the state of the system.
-     * If some other constraints above cannot be satisfied, -EINVAL is returned.
+     * When timeout is not 0:
+     *   If successful, 0 is returned.
+     *   If the specified sensor doesn't support batch mode, return -EINVAL.
+     *   If the specified sensor's trigger-mode is one-shot, return -EINVAL.
+     *   If WAKE_UPON_FIFO_FULL is specified and the specified sensor's internal
+     *   FIFO is too small to store at least 10 seconds worth of data at the
+     *   given rate, -EINVAL is returned. Note that as stated above, this has to
+     *   be determined at compile time, and not based on the state of the
+     *   system.
+     *   If some other constraints above cannot be satisfied, return -EINVAL.
      *
      * Note: the timeout parameter, when > 0, has no impact on whether this
      *       function succeeds or fails.
      *
-     * If timeout is set to 0, this function must succeed.
+     * When timeout is 0:
+     *   The caller will never set the wake_upon_fifo_full flag.
+     *   The function must succeed, and batch mode must be deactivated.
+     *
+     * Independently of whether DRY_RUN is specified, When the call to batch()
+     * fails, no state should be changed. In particular, a failed call to
+     * batch() should not change the rate of the sensor. Example:
+     *   setDelay(..., 10ms)
+     *   batch(..., 20ms, ...) fails
+     *   rate should stay 10ms.
      *
      *
      * IMPLEMENTATION NOTES:
diff --git a/modules/audio/audio_policy.c b/modules/audio/audio_policy.c
index 2dd3dbe..9335654 100644
--- a/modules/audio/audio_policy.c
+++ b/modules/audio/audio_policy.c
@@ -99,7 +99,8 @@
                                        uint32_t sampling_rate,
                                        audio_format_t format,
                                        audio_channel_mask_t channelMask,
-                                       audio_output_flags_t flags)
+                                       audio_output_flags_t flags,
+                                       const audio_offload_info_t *info)
 {
     return 0;
 }
@@ -229,6 +230,12 @@
     return -ENOSYS;
 }
 
+static bool ap_is_offload_supported(const struct audio_policy *pol,
+                                   const audio_offload_info_t *info)
+{
+    return false;
+}
+
 static int create_default_ap(const struct audio_policy_device *device,
                              struct audio_policy_service_ops *aps_ops,
                              void *service,
@@ -278,6 +285,8 @@
     dap->policy.is_stream_active = ap_is_stream_active;
     dap->policy.dump = ap_dump;
 
+    dap->policy.is_offload_supported = ap_is_offload_supported;
+
     dap->service = service;
     dap->aps_ops = aps_ops;
 
diff --git a/modules/camera/Android.mk b/modules/camera/Android.mk
index 5d26934..e02a143 100644
--- a/modules/camera/Android.mk
+++ b/modules/camera/Android.mk
@@ -26,6 +26,7 @@
 LOCAL_SRC_FILES := \
 	CameraHAL.cpp \
 	Camera.cpp \
+	Metadata.cpp \
 	Stream.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/modules/camera/Camera.cpp b/modules/camera/Camera.cpp
index 718d42b..2fe7395 100644
--- a/modules/camera/Camera.cpp
+++ b/modules/camera/Camera.cpp
@@ -19,7 +19,9 @@
 #include <hardware/camera3.h>
 #include <sync/sync.h>
 #include <system/camera_metadata.h>
+#include <system/graphics.h>
 #include "CameraHAL.h"
+#include "Metadata.h"
 #include "Stream.h"
 
 //#define LOG_NDEBUG 0
@@ -34,6 +36,8 @@
 
 #define CAMERA_SYNC_TIMEOUT 5000 // in msecs
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
 namespace default_camera_hal {
 
 extern "C" {
@@ -48,6 +52,7 @@
 
 Camera::Camera(int id)
   : mId(id),
+    mStaticInfo(NULL),
     mBusy(false),
     mCallbackOps(NULL),
     mStreams(NULL),
@@ -59,6 +64,7 @@
 
     memset(&mDevice, 0, sizeof(mDevice));
     mDevice.common.tag    = HARDWARE_DEVICE_TAG;
+    mDevice.common.version = CAMERA_DEVICE_API_VERSION_3_0;
     mDevice.common.close  = close_device;
     mDevice.ops           = const_cast<camera3_device_ops_t*>(&sOps);
     mDevice.priv          = this;
@@ -88,6 +94,25 @@
     return 0;
 }
 
+int Camera::getInfo(struct camera_info *info)
+{
+    int ret = 0;
+
+    info->facing = CAMERA_FACING_FRONT;
+    info->orientation = 0;
+    info->device_version = mDevice.common.version;
+
+    pthread_mutex_lock(&mMutex);
+    if (mStaticInfo == NULL) {
+        ret = initStaticInfo();
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    info->static_camera_characteristics = mStaticInfo;
+
+    return ret;
+}
+
 int Camera::close()
 {
     ALOGI("%s:%d: Closing camera device", __func__, mId);
@@ -110,6 +135,164 @@
 {
     ALOGV("%s:%d: callback_ops=%p", __func__, mId, callback_ops);
     mCallbackOps = callback_ops;
+    // Create standard settings templates
+    // 0 is invalid as template
+    mTemplates[0] = NULL;
+    // CAMERA3_TEMPLATE_PREVIEW = 1
+    mTemplates[1] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+            ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW);
+    // CAMERA3_TEMPLATE_STILL_CAPTURE = 2
+    mTemplates[2] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+            ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
+    // CAMERA3_TEMPLATE_VIDEO_RECORD = 3
+    mTemplates[3] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+            ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
+    // CAMERA3_TEMPLATE_VIDEO_SNAPSHOT = 4
+    mTemplates[4] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+            ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
+    // CAMERA3_TEMPLATE_STILL_ZERO_SHUTTER_LAG = 5
+    mTemplates[5] = new Metadata(ANDROID_CONTROL_MODE_OFF,
+            ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG);
+    // Pre-generate metadata structures
+    for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
+        mTemplates[i]->generate();
+    }
+    // TODO: create vendor templates
+    return 0;
+}
+
+int Camera::initStaticInfo()
+{
+    /*
+     * Setup static camera info.  This will have to customized per camera
+     * device.
+     */
+
+    /* android.control */
+    int32_t android_control_ae_available_target_fps_ranges[] = {30, 30};
+    mMetadata.addInt32(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+            ARRAY_SIZE(android_control_ae_available_target_fps_ranges),
+            android_control_ae_available_target_fps_ranges);
+
+    int32_t android_control_ae_compensation_range[] = {-4, 4};
+    mMetadata.addInt32(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+            ARRAY_SIZE(android_control_ae_compensation_range),
+            android_control_ae_compensation_range);
+
+    camera_metadata_rational_t android_control_ae_compensation_step[] = {{2,1}};
+    mMetadata.addRational(ANDROID_CONTROL_AE_COMPENSATION_STEP,
+            ARRAY_SIZE(android_control_ae_compensation_step),
+            android_control_ae_compensation_step);
+
+    int32_t android_control_max_regions[] = {1};
+    mMetadata.addInt32(ANDROID_CONTROL_MAX_REGIONS,
+            ARRAY_SIZE(android_control_max_regions),
+            android_control_max_regions);
+
+    /* android.jpeg */
+    int32_t android_jpeg_available_thumbnail_sizes[] = {0, 0, 128, 96};
+    mMetadata.addInt32(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+            ARRAY_SIZE(android_jpeg_available_thumbnail_sizes),
+            android_jpeg_available_thumbnail_sizes);
+
+    /* android.lens */
+    float android_lens_info_available_focal_lengths[] = {1.0};
+    mMetadata.addFloat(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
+            ARRAY_SIZE(android_lens_info_available_focal_lengths),
+            android_lens_info_available_focal_lengths);
+
+    /* android.request */
+    int32_t android_request_max_num_output_streams[] = {0, 3, 1};
+    mMetadata.addInt32(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+            ARRAY_SIZE(android_request_max_num_output_streams),
+            android_request_max_num_output_streams);
+
+    /* android.scaler */
+    int32_t android_scaler_available_formats[] = {
+            HAL_PIXEL_FORMAT_RAW_SENSOR,
+            HAL_PIXEL_FORMAT_BLOB,
+            HAL_PIXEL_FORMAT_RGBA_8888,
+            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+            // These are handled by YCbCr_420_888
+            //        HAL_PIXEL_FORMAT_YV12,
+            //        HAL_PIXEL_FORMAT_YCrCb_420_SP,
+            HAL_PIXEL_FORMAT_YCbCr_420_888};
+    mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_FORMATS,
+            ARRAY_SIZE(android_scaler_available_formats),
+            android_scaler_available_formats);
+
+    int64_t android_scaler_available_jpeg_min_durations[] = {1};
+    mMetadata.addInt64(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
+            ARRAY_SIZE(android_scaler_available_jpeg_min_durations),
+            android_scaler_available_jpeg_min_durations);
+
+    int32_t android_scaler_available_jpeg_sizes[] = {640, 480};
+    mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
+            ARRAY_SIZE(android_scaler_available_jpeg_sizes),
+            android_scaler_available_jpeg_sizes);
+
+    float android_scaler_available_max_digital_zoom[] = {1};
+    mMetadata.addFloat(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+            ARRAY_SIZE(android_scaler_available_max_digital_zoom),
+            android_scaler_available_max_digital_zoom);
+
+    int64_t android_scaler_available_processed_min_durations[] = {1};
+    mMetadata.addInt64(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
+            ARRAY_SIZE(android_scaler_available_processed_min_durations),
+            android_scaler_available_processed_min_durations);
+
+    int32_t android_scaler_available_processed_sizes[] = {640, 480};
+    mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
+            ARRAY_SIZE(android_scaler_available_processed_sizes),
+            android_scaler_available_processed_sizes);
+
+    int64_t android_scaler_available_raw_min_durations[] = {1};
+    mMetadata.addInt64(ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
+            ARRAY_SIZE(android_scaler_available_raw_min_durations),
+            android_scaler_available_raw_min_durations);
+
+    int32_t android_scaler_available_raw_sizes[] = {640, 480};
+    mMetadata.addInt32(ANDROID_SCALER_AVAILABLE_RAW_SIZES,
+            ARRAY_SIZE(android_scaler_available_raw_sizes),
+            android_scaler_available_raw_sizes);
+
+    /* android.sensor */
+
+    int32_t android_sensor_info_active_array_size[] = {0, 0, 640, 480};
+    mMetadata.addInt32(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+            ARRAY_SIZE(android_sensor_info_active_array_size),
+            android_sensor_info_active_array_size);
+
+    int32_t android_sensor_info_sensitivity_range[] =
+            {100, 1600};
+    mMetadata.addInt32(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
+            ARRAY_SIZE(android_sensor_info_sensitivity_range),
+            android_sensor_info_sensitivity_range);
+
+    int64_t android_sensor_info_max_frame_duration[] = {30000000000};
+    mMetadata.addInt64(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+            ARRAY_SIZE(android_sensor_info_max_frame_duration),
+            android_sensor_info_max_frame_duration);
+
+    float android_sensor_info_physical_size[] = {3.2, 2.4};
+    mMetadata.addFloat(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
+            ARRAY_SIZE(android_sensor_info_physical_size),
+            android_sensor_info_physical_size);
+
+    int32_t android_sensor_info_pixel_array_size[] = {640, 480};
+    mMetadata.addInt32(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+            ARRAY_SIZE(android_sensor_info_pixel_array_size),
+            android_sensor_info_pixel_array_size);
+
+    int32_t android_sensor_orientation[] = {0};
+    mMetadata.addInt32(ANDROID_SENSOR_ORIENTATION,
+            ARRAY_SIZE(android_sensor_orientation),
+            android_sensor_orientation);
+
+    /* End of static camera characteristics */
+
+    mStaticInfo = mMetadata.generate();
+
     return 0;
 }
 
@@ -141,12 +324,15 @@
     for (int i = 0; i < mNumStreams; i++)
         mStreams[i]->mReuse = false;
     // Fill new stream array with reused streams and new streams
-    for (int i = 0; i < stream_config->num_streams; i++) {
+    for (unsigned int i = 0; i < stream_config->num_streams; i++) {
         astream = stream_config->streams[i];
-        if (astream->max_buffers > 0)
+        if (astream->max_buffers > 0) {
+            ALOGV("%s:%d: Reusing stream %d", __func__, mId, i);
             newStreams[i] = reuseStream(astream);
-        else
+        } else {
+            ALOGV("%s:%d: Creating new stream %d", __func__, mId, i);
             newStreams[i] = new Stream(mId, astream);
+        }
 
         if (newStreams[i] == NULL) {
             ALOGE("%s:%d: Error processing stream %d", __func__, mId, i);
@@ -228,6 +414,8 @@
         if (streams[i]->isOutputType())
             outputs++;
     }
+    ALOGV("%s:%d: Configuring %d output streams and %d input streams",
+            __func__, mId, outputs, inputs);
     if (outputs < 1) {
         ALOGE("%s:%d: Stream config must have >= 1 output", __func__, mId);
         return false;
@@ -285,8 +473,12 @@
 const camera_metadata_t* Camera::constructDefaultRequestSettings(int type)
 {
     ALOGV("%s:%d: type=%d", __func__, mId, type);
-    // TODO: return statically built default request
-    return NULL;
+
+    if (type < 1 || type >= CAMERA3_TEMPLATE_COUNT) {
+        ALOGE("%s:%d: Invalid template request type: %d", __func__, mId, type);
+        return NULL;
+    }
+    return mTemplates[type]->generate();
 }
 
 int Camera::processCaptureRequest(camera3_capture_request_t *request)
@@ -352,6 +544,7 @@
     // TODO: return actual captured/reprocessed settings
     result.result = request->settings;
     // TODO: asynchronously return results
+    notifyShutter(request->frame_number, 0);
     mCallbackOps->process_capture_result(mCallbackOps, &result);
 
     return 0;
@@ -373,13 +566,13 @@
         mSettings = clone_camera_metadata(new_settings);
 }
 
-bool Camera::isValidCaptureSettings(const camera_metadata_t *settings)
+bool Camera::isValidCaptureSettings(const camera_metadata_t* /*settings*/)
 {
     // TODO: reject settings that cannot be captured
     return true;
 }
 
-bool Camera::isValidReprocessSettings(const camera_metadata_t *settings)
+bool Camera::isValidReprocessSettings(const camera_metadata_t* /*settings*/)
 {
     // TODO: reject settings that cannot be reprocessed
     // input buffers unimplemented, use this to reject reprocessing requests
@@ -390,14 +583,17 @@
 int Camera::processCaptureBuffer(const camera3_stream_buffer_t *in,
         camera3_stream_buffer_t *out)
 {
-    int res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT);
-    if (res == -ETIME) {
-        ALOGE("%s:%d: Timeout waiting on buffer acquire fence", __func__, mId);
-        return res;
-    } else if (res) {
-        ALOGE("%s:%d: Error waiting on buffer acquire fence: %s(%d)",
-                __func__, mId, strerror(-res), res);
-        return res;
+    if (in->acquire_fence != -1) {
+        int res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT);
+        if (res == -ETIME) {
+            ALOGE("%s:%d: Timeout waiting on buffer acquire fence",
+                    __func__, mId);
+            return res;
+        } else if (res) {
+            ALOGE("%s:%d: Error waiting on buffer acquire fence: %s(%d)",
+                    __func__, mId, strerror(-res), res);
+            return res;
+        }
     }
 
     out->stream = in->stream;
@@ -411,6 +607,31 @@
     return 0;
 }
 
+void Camera::notifyShutter(uint32_t frame_number, uint64_t timestamp)
+{
+    int res;
+    struct timespec ts;
+
+    // If timestamp is 0, get timestamp from right now instead
+    if (timestamp == 0) {
+        ALOGW("%s:%d: No timestamp provided, using CLOCK_BOOTTIME",
+                __func__, mId);
+        res = clock_gettime(CLOCK_BOOTTIME, &ts);
+        if (res == 0) {
+            timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+        } else {
+            ALOGE("%s:%d: No timestamp and failed to get CLOCK_BOOTTIME %s(%d)",
+                    __func__, mId, strerror(errno), errno);
+        }
+    }
+    camera3_notify_msg_t m;
+    memset(&m, 0, sizeof(m));
+    m.type = CAMERA3_MSG_SHUTTER;
+    m.message.shutter.frame_number = frame_number;
+    m.message.shutter.timestamp = timestamp;
+    mCallbackOps->notify(mCallbackOps, &m);
+}
+
 void Camera::getMetadataVendorTagOps(vendor_tag_query_ops_t *ops)
 {
     ALOGV("%s:%d: ops=%p", __func__, mId, ops);
diff --git a/modules/camera/Camera.h b/modules/camera/Camera.h
index 4001453..16e1439 100644
--- a/modules/camera/Camera.h
+++ b/modules/camera/Camera.h
@@ -20,6 +20,7 @@
 #include <pthread.h>
 #include <hardware/hardware.h>
 #include <hardware/camera3.h>
+#include "Metadata.h"
 #include "Stream.h"
 
 namespace default_camera_hal {
@@ -36,6 +37,7 @@
 
         // Common Camera Device Operations (see <hardware/camera_common.h>)
         int open(const hw_module_t *module, hw_device_t **device);
+        int getInfo(struct camera_info *info);
         int close();
 
         // Camera v3 Device Operations (see <hardware/camera3.h>)
@@ -51,6 +53,8 @@
         camera3_device_t mDevice;
 
     private:
+        // Separate initialization method for static metadata
+        int initStaticInfo();
         // Reuse a stream already created by this device
         Stream *reuseStream(camera3_stream_t *astream);
         // Destroy all streams in a stream array, and the array itself
@@ -68,9 +72,15 @@
         // Process an output buffer
         int processCaptureBuffer(const camera3_stream_buffer_t *in,
                 camera3_stream_buffer_t *out);
+        // Send a shutter notify message with start of exposure time
+        void notifyShutter(uint32_t frame_number, uint64_t timestamp);
 
         // Identifier used by framework to distinguish cameras
         const int mId;
+        // Metadata containing persistent camera characteristics
+        Metadata mMetadata;
+        // camera_metadata structure containing static characteristics
+        camera_metadata_t *mStaticInfo;
         // Busy flag indicates camera is in use
         bool mBusy;
         // Camera device operations handle shared by all devices
@@ -83,6 +93,8 @@
         Stream **mStreams;
         // Number of streams in mStreams
         int mNumStreams;
+        // Static array of standard camera settings templates
+        Metadata *mTemplates[CAMERA3_TEMPLATE_COUNT];
         // Most recent request settings seen, memoized to be reused
         camera_metadata_t *mSettings;
 };
diff --git a/modules/camera/CameraHAL.cpp b/modules/camera/CameraHAL.cpp
index 05b1fad..dfbbe4c 100644
--- a/modules/camera/CameraHAL.cpp
+++ b/modules/camera/CameraHAL.cpp
@@ -76,7 +76,7 @@
         return -ENODEV;
     }
     // TODO: return device-specific static metadata
-    return 0;
+    return mCameras[id]->getInfo(info);
 }
 
 int CameraHAL::setCallbacks(const camera_module_callbacks_t *callbacks)
@@ -92,8 +92,12 @@
     char *nameEnd;
 
     ALOGV("%s: module=%p, name=%s, device=%p", __func__, mod, name, dev);
+    if (*name == '\0') {
+        ALOGE("%s: Invalid camera id name is NULL", __func__);
+        return -EINVAL;
+    }
     id = strtol(name, &nameEnd, 10);
-    if (nameEnd != NULL) {
+    if (*nameEnd != '\0') {
         ALOGE("%s: Invalid camera id name %s", __func__, name);
         return -EINVAL;
     } else if (id < 0 || id >= mNumberOfCameras) {
diff --git a/modules/camera/Metadata.cpp b/modules/camera/Metadata.cpp
new file mode 100644
index 0000000..d5854f9
--- /dev/null
+++ b/modules/camera/Metadata.cpp
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+
+#include <pthread.h>
+#include <system/camera_metadata.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Metadata"
+#include <cutils/log.h>
+
+#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
+#include <cutils/trace.h>
+#include "ScopedTrace.h"
+
+#include "Metadata.h"
+
+namespace default_camera_hal {
+
+Metadata::Metadata()
+  : mHead(NULL),
+    mTail(NULL),
+    mEntryCount(0),
+    mDataCount(0),
+    mGenerated(NULL),
+    mDirty(true)
+{
+    // NULL (default) pthread mutex attributes
+    pthread_mutex_init(&mMutex, NULL);
+}
+
+Metadata::~Metadata()
+{
+    Entry *current = mHead;
+
+    while (current != NULL) {
+        Entry *tmp = current;
+        current = current->mNext;
+        delete tmp;
+    }
+
+    if (mGenerated != NULL)
+        free_camera_metadata(mGenerated);
+
+    pthread_mutex_destroy(&mMutex);
+}
+
+Metadata::Metadata(uint8_t mode, uint8_t intent)
+  : mHead(NULL),
+    mTail(NULL),
+    mEntryCount(0),
+    mDataCount(0),
+    mGenerated(NULL),
+    mDirty(true)
+{
+    pthread_mutex_init(&mMutex, NULL);
+
+    if (validate(ANDROID_CONTROL_MODE, TYPE_BYTE, 1)) {
+        int res = add(ANDROID_CONTROL_MODE, 1, &mode);
+        if (res != 0) {
+            ALOGE("%s: Unable to add mode to template!", __func__);
+        }
+    } else {
+        ALOGE("%s: Invalid mode constructing template!", __func__);
+    }
+
+    if (validate(ANDROID_CONTROL_CAPTURE_INTENT, TYPE_BYTE, 1)) {
+        int res = add(ANDROID_CONTROL_CAPTURE_INTENT, 1, &intent);
+        if (res != 0) {
+            ALOGE("%s: Unable to add capture intent to template!", __func__);
+        }
+    } else {
+        ALOGE("%s: Invalid capture intent constructing template!", __func__);
+    }
+}
+
+int Metadata::addUInt8(uint32_t tag, int count, uint8_t *data)
+{
+    if (!validate(tag, TYPE_BYTE, count)) return -EINVAL;
+    return add(tag, count, data);
+}
+
+int Metadata::addInt32(uint32_t tag, int count, int32_t *data)
+{
+    if (!validate(tag, TYPE_INT32, count)) return -EINVAL;
+    return add(tag, count, data);
+}
+
+int Metadata::addFloat(uint32_t tag, int count, float *data)
+{
+    if (!validate(tag, TYPE_FLOAT, count)) return -EINVAL;
+    return add(tag, count, data);
+}
+
+int Metadata::addInt64(uint32_t tag, int count, int64_t *data)
+{
+    if (!validate(tag, TYPE_INT64, count)) return -EINVAL;
+    return add(tag, count, data);
+}
+
+int Metadata::addDouble(uint32_t tag, int count, double *data)
+{
+    if (!validate(tag, TYPE_DOUBLE, count)) return -EINVAL;
+    return add(tag, count, data);
+}
+
+int Metadata::addRational(uint32_t tag, int count,
+        camera_metadata_rational_t *data)
+{
+    if (!validate(tag, TYPE_RATIONAL, count)) return -EINVAL;
+    return add(tag, count, data);
+}
+
+bool Metadata::validate(uint32_t tag, int tag_type, int count)
+{
+    if (get_camera_metadata_tag_type(tag) < 0) {
+        ALOGE("%s: Invalid metadata entry tag: %d", __func__, tag);
+        return false;
+    }
+    if (tag_type < 0 || tag_type >= NUM_TYPES) {
+        ALOGE("%s: Invalid metadata entry tag type: %d", __func__, tag_type);
+        return false;
+    }
+    if (tag_type != get_camera_metadata_tag_type(tag)) {
+        ALOGE("%s: Tag %d called with incorrect type: %s(%d)", __func__, tag,
+                camera_metadata_type_names[tag_type], tag_type);
+        return false;
+    }
+    if (count < 1) {
+        ALOGE("%s: Invalid metadata entry count: %d", __func__, count);
+        return false;
+    }
+    return true;
+}
+
+int Metadata::add(uint32_t tag, int count, void *tag_data)
+{
+    int tag_type = get_camera_metadata_tag_type(tag);
+    size_t type_sz = camera_metadata_type_size[tag_type];
+
+    // Allocate array to hold new metadata
+    void *data = malloc(count * type_sz);
+    if (data == NULL)
+        return -ENOMEM;
+    memcpy(data, tag_data, count * type_sz);
+
+    pthread_mutex_lock(&mMutex);
+    mEntryCount++;
+    mDataCount += calculate_camera_metadata_entry_data_size(tag_type, count);
+    push(new Entry(tag, data, count));
+    mDirty = true;
+    pthread_mutex_unlock(&mMutex);
+    return 0;
+}
+
+camera_metadata_t* Metadata::generate()
+{
+    pthread_mutex_lock(&mMutex);
+    // Reuse if old generated metadata still valid
+    if (!mDirty && mGenerated != NULL) {
+        ALOGV("%s: Reusing generated metadata at %p", __func__, mGenerated);
+        goto out;
+    }
+    // Destroy old metadata
+    if (mGenerated != NULL) {
+        ALOGV("%s: Freeing generated metadata at %p", __func__, mGenerated);
+        free_camera_metadata(mGenerated);
+        mGenerated = NULL;
+    }
+    // Generate new metadata structure
+    ALOGV("%s: Generating new camera metadata structure, Entries:%d Data:%d",
+            __func__, mEntryCount, mDataCount);
+    mGenerated = allocate_camera_metadata(mEntryCount, mDataCount);
+    if (mGenerated == NULL) {
+        ALOGE("%s: Failed to allocate metadata (%d entries %d data)",
+                __func__, mEntryCount, mDataCount);
+        goto out;
+    }
+    // Walk list of entries adding each one to newly allocated metadata
+    for (Entry *current = mHead; current != NULL; current = current->mNext) {
+        int res = add_camera_metadata_entry(mGenerated, current->mTag,
+                current->mData, current->mCount);
+        if (res != 0) {
+            ALOGE("%s: Failed to add camera metadata: %d", __func__, res);
+            free_camera_metadata(mGenerated);
+            mGenerated = NULL;
+            goto out;
+        }
+    }
+
+out:
+    pthread_mutex_unlock(&mMutex);
+    return mGenerated;
+}
+
+Metadata::Entry::Entry(uint32_t tag, void *data, int count)
+  : mNext(NULL),
+    mPrev(NULL),
+    mTag(tag),
+    mData(data),
+    mCount(count)
+{
+}
+
+void Metadata::push(Entry *e)
+{
+    if (mHead == NULL) {
+        mHead = mTail = e;
+    } else {
+        mTail->insertAfter(e);
+        mTail = e;
+    }
+}
+
+Metadata::Entry::~Entry()
+{
+    if (mNext != NULL)
+        mNext->mPrev = mPrev;
+    if (mPrev != NULL)
+        mPrev->mNext = mNext;
+}
+
+void Metadata::Entry::insertAfter(Entry *e)
+{
+    if (e == NULL)
+        return;
+    if (mNext != NULL)
+        mNext->mPrev = e;
+    e->mNext = mNext;
+    e->mPrev = this;
+    mNext = e;
+}
+
+} // namespace default_camera_hal
diff --git a/modules/camera/Metadata.h b/modules/camera/Metadata.h
new file mode 100644
index 0000000..22d2f22
--- /dev/null
+++ b/modules/camera/Metadata.h
@@ -0,0 +1,79 @@
+/*
+ * 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 METADATA_H_
+#define METADATA_H_
+
+#include <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/camera_metadata.h>
+#include <system/graphics.h>
+
+namespace default_camera_hal {
+// Metadata is a convenience class for dealing with libcamera_metadata
+class Metadata {
+    public:
+        Metadata();
+        ~Metadata();
+        // Constructor used for request metadata templates
+        Metadata(uint8_t mode, uint8_t intent);
+
+        // Parse and add an entry
+        int addUInt8(uint32_t tag, int count, uint8_t *data);
+        int addInt32(uint32_t tag, int count, int32_t *data);
+        int addFloat(uint32_t tag, int count, float *data);
+        int addInt64(uint32_t tag, int count, int64_t *data);
+        int addDouble(uint32_t tag, int count, double *data);
+        int addRational(uint32_t tag, int count,
+                camera_metadata_rational_t *data);
+        // Generate a camera_metadata structure and fill it with internal data
+        camera_metadata_t *generate();
+
+    private:
+        // Validate the tag, type and count for a metadata entry
+        bool validate(uint32_t tag, int tag_type, int count);
+        // Add a verified tag with data to this Metadata structure
+        int add(uint32_t tag, int count, void *tag_data);
+
+        class Entry {
+            public:
+                Entry(uint32_t tag, void *data, int count);
+                ~Entry();
+                Entry *mNext;
+                Entry *mPrev;
+                const uint32_t mTag;
+                const void *mData;
+                const int mCount;
+                void insertAfter(Entry *e);
+        };
+        // List ends
+        Entry *mHead;
+        Entry *mTail;
+        // Append entry to list
+        void push(Entry *e);
+        // Total of entries and entry data size
+        int mEntryCount;
+        int mDataCount;
+        // Save generated metadata, invalidated on update
+        camera_metadata_t *mGenerated;
+        // Flag to force metadata regeneration
+        bool mDirty;
+        // Lock protecting the Metadata object for modifications
+        pthread_mutex_t mMutex;
+};
+} // namespace default_camera_hal
+
+#endif // METADATA_H_
diff --git a/modules/camera/Stream.cpp b/modules/camera/Stream.cpp
index 0834aee..aae7adb 100644
--- a/modules/camera/Stream.cpp
+++ b/modules/camera/Stream.cpp
@@ -61,6 +61,7 @@
     pthread_mutex_lock(&mMutex);
     if (usage != mUsage) {
         mUsage = usage;
+        mStream->usage = usage;
         unregisterBuffers_L();
     }
     pthread_mutex_unlock(&mMutex);
@@ -71,6 +72,7 @@
     pthread_mutex_lock(&mMutex);
     if (max_buffers != mMaxBuffers) {
         mMaxBuffers = max_buffers;
+        mStream->max_buffers = max_buffers;
         unregisterBuffers_L();
     }
     pthread_mutex_unlock(&mMutex);
@@ -83,12 +85,14 @@
 
 bool Stream::isInputType()
 {
-    return mType & (CAMERA3_STREAM_INPUT | CAMERA3_STREAM_BIDIRECTIONAL);
+    return mType == CAMERA3_STREAM_INPUT ||
+        mType == CAMERA3_STREAM_BIDIRECTIONAL;
 }
 
 bool Stream::isOutputType()
 {
-    return mType & (CAMERA3_STREAM_OUTPUT | CAMERA3_STREAM_BIDIRECTIONAL);
+    return mType == CAMERA3_STREAM_OUTPUT ||
+        mType == CAMERA3_STREAM_BIDIRECTIONAL;
 }
 
 bool Stream::isRegistered()
diff --git a/modules/camera/Stream.h b/modules/camera/Stream.h
index 521362e..34abd95 100644
--- a/modules/camera/Stream.h
+++ b/modules/camera/Stream.h
@@ -52,7 +52,7 @@
         // The camera device id this stream belongs to
         const int mId;
         // Handle to framework's stream, used as a cookie for buffers
-        const camera3_stream_t *mStream;
+        camera3_stream_t *mStream;
         // Stream type: CAMERA3_STREAM_* (see <hardware/camera3.h>)
         const int mType;
         // Width in pixels of the buffers in this stream
diff --git a/tests/camera2/CameraBurstTests.cpp b/tests/camera2/CameraBurstTests.cpp
index e39970c..cf8f68a 100644
--- a/tests/camera2/CameraBurstTests.cpp
+++ b/tests/camera2/CameraBurstTests.cpp
@@ -19,13 +19,14 @@
 #define LOG_TAG "CameraBurstTest"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
+#include <utils/Timers.h>
 
 #include <cmath>
 
 #include "CameraStreamFixture.h"
 #include "TestExtensions.h"
 
-#define CAMERA_FRAME_TIMEOUT    1000000000 //nsecs (1 secs)
+#define CAMERA_FRAME_TIMEOUT    1000000000LL //nsecs (1 secs)
 #define CAMERA_HEAP_COUNT       2 //HALBUG: 1 means registerBuffers fails
 #define CAMERA_BURST_DEBUGGING  0
 #define CAMERA_FRAME_BURST_COUNT 10
@@ -34,9 +35,13 @@
 #define CAMERA_EXPOSURE_DOUBLE  2
 #define CAMERA_EXPOSURE_DOUBLING_THRESHOLD 1.0f
 #define CAMERA_EXPOSURE_DOUBLING_COUNT 4
-#define CAMERA_EXPOSURE_FORMAT HAL_PIXEL_FORMAT_YCrCb_420_SP
+#define CAMERA_EXPOSURE_FORMAT CAMERA_STREAM_AUTO_CPU_FORMAT
 #define CAMERA_EXPOSURE_STARTING 100000 // 1/10ms, up to 51.2ms with 10 steps
 
+#define USEC 1000LL        // in ns
+#define MSEC 1000000LL     // in ns
+#define SEC  1000000000LL  // in ns
+
 #if CAMERA_BURST_DEBUGGING
 #define dout std::cout
 #else
@@ -86,7 +91,7 @@
         TEST_EXTENSION_FORKING_TEAR_DOWN;
     }
 
-    /* this assumes the format is YUV420sp */
+    /* this assumes the format is YUV420sp or flexible YUV */
     long long TotalBrightness(const CpuConsumer::LockedBuffer& imgBuffer,
                               int *underexposed,
                               int *overexposed) const {
@@ -122,6 +127,23 @@
 
         return acc;
     }
+
+    // Parses a comma-separated string list into a Vector
+    template<typename T>
+    void ParseList(const char *src, Vector<T> &list) {
+        std::istringstream s(src);
+        while (!s.eof()) {
+            char c = s.peek();
+            if (c == ',' || c == ' ') {
+                s.ignore(1, EOF);
+                continue;
+            }
+            T val;
+            s >> val;
+            list.push_back(val);
+        }
+    }
+
 };
 
 TEST_F(CameraBurstTest, ManualExposureControl) {
@@ -170,6 +192,11 @@
         uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
         ASSERT_EQ(OK, previewRequest.update(ANDROID_CONTROL_MODE,
                                             &cmOff, 1));
+
+        int requestId = 1;
+        ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_ID,
+                                            &requestId, 1));
+
         if (CAMERA_BURST_DEBUGGING) {
             int frameCount = 0;
             ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_FRAME_COUNT,
@@ -252,7 +279,415 @@
       << " times over each consecutive frame as the exposure is doubled";
 }
 
-}
-}
+/**
+ * This test varies exposure time, frame duration, and sensitivity for a
+ * burst of captures. It picks values by default, but the selection can be
+ * overridden with the environment variables
+ *   CAMERA2_TEST_VARIABLE_BURST_EXPOSURE_TIMES
+ *   CAMERA2_TEST_VARIABLE_BURST_FRAME_DURATIONS
+ *   CAMERA2_TEST_VARIABLE_BURST_SENSITIVITIES
+ * which must all be a list of comma-separated values, and each list must be
+ * the same length.  In addition, if the environment variable
+ *   CAMERA2_TEST_VARIABLE_BURST_DUMP_FRAMES
+ * is set to 1, then the YUV buffers are dumped into files named
+ *   "camera2_test_variable_burst_frame_NNN.yuv"
+ *
+ * For example:
+ *   $ setenv CAMERA2_TEST_VARIABLE_BURST_EXPOSURE_TIMES 10000000,20000000
+ *   $ setenv CAMERA2_TEST_VARIABLE_BURST_FRAME_DURATIONS 40000000,40000000
+ *   $ setenv CAMERA2_TEST_VARIABLE_BURST_SENSITIVITIES 200,100
+ *   $ setenv CAMERA2_TEST_VARIABLE_BURST_DUMP_FRAMES 1
+ *   $ /data/nativetest/camera2_test/camera2_test --gtest_filter="*VariableBurst"
+ */
+TEST_F(CameraBurstTest, VariableBurst) {
+
+    TEST_EXTENSION_FORKING_INIT;
+
+    // Bounds for checking frame duration is within range
+    const nsecs_t DURATION_UPPER_BOUND = 10 * MSEC;
+    const nsecs_t DURATION_LOWER_BOUND = 20 * MSEC;
+
+    // Threshold for considering two captures to have equivalent exposure value,
+    // as a ratio of the smaller EV to the larger EV.
+    const float   EV_MATCH_BOUND = 0.95;
+    // Bound for two captures with equivalent exp values to have the same
+    // measured brightness, in 0-255 luminance.
+    const float   BRIGHTNESS_MATCH_BOUND = 5;
+
+    // Environment variables to look for to override test settings
+    const char *expEnv         = "CAMERA2_TEST_VARIABLE_BURST_EXPOSURE_TIMES";
+    const char *durationEnv    = "CAMERA2_TEST_VARIABLE_BURST_FRAME_DURATIONS";
+    const char *sensitivityEnv = "CAMERA2_TEST_VARIABLE_BURST_SENSITIVITIES";
+    const char *dumpFrameEnv   = "CAMERA2_TEST_VARIABLE_BURST_DUMP_FRAMES";
+
+    // Range of valid exposure times, in nanoseconds
+    int64_t minExp = 0, maxExp = 0;
+    // List of valid sensor sensitivities
+    Vector<int32_t> sensitivities;
+    // Range of valid frame durations, in nanoseconds
+    int64_t minDuration = 0, maxDuration = 0;
+
+    {
+        camera_metadata_ro_entry exposureTimeRange =
+            GetStaticEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE);
+
+        EXPECT_EQ(2u, exposureTimeRange.count) << "Bad exposure time range tag."
+                "Using default values";
+        if (exposureTimeRange.count == 2) {
+            minExp = exposureTimeRange.data.i64[0];
+            maxExp = exposureTimeRange.data.i64[1];
+        }
+
+        EXPECT_LT(0, minExp) << "Minimum exposure time is 0";
+        EXPECT_LT(0, maxExp) << "Maximum exposure time is 0";
+        EXPECT_LE(minExp, maxExp) << "Minimum exposure is greater than maximum";
+
+        if (minExp == 0) {
+            minExp = 1 * MSEC; // Fallback minimum exposure time
+        }
+
+        if (maxExp == 0) {
+            maxExp = 10 * SEC; // Fallback maximum exposure time
+        }
+    }
+
+    dout << "Stream size is " << mWidth << " x " << mHeight << std::endl;
+    dout << "Valid exposure range is: " <<
+            minExp << " - " << maxExp << " ns " << std::endl;
+
+    {
+        camera_metadata_ro_entry sensivityRange =
+            GetStaticEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE);
+        EXPECT_EQ(2u, sensivityRange.count) << "No sensitivity range listed."
+                "Falling back to default set.";
+        int32_t minSensitivity = 100;
+        int32_t maxSensitivity = 800;
+        if (sensivityRange.count >= 2) {
+            minSensitivity = sensivityRange.data.i32[0];
+            maxSensitivity = sensivityRange.data.i32[1];
+        }
+        int32_t count = (maxSensitivity - minSensitivity + 99) / 100;
+        sensitivities.push_back(minSensitivity);
+        for (int i = 1; i < count; i++) {
+            sensitivities.push_back(minSensitivity + i * 100);
+        }
+        sensitivities.push_back(maxSensitivity);
+    }
+
+    dout << "Available sensitivities: ";
+    for (size_t i = 0; i < sensitivities.size(); i++) {
+        dout << sensitivities[i] << " ";
+    }
+    dout << std::endl;
+
+    {
+        camera_metadata_ro_entry availableProcessedSizes =
+                GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+
+        camera_metadata_ro_entry availableProcessedMinFrameDurations =
+                GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS);
+
+        EXPECT_EQ(availableProcessedSizes.count,
+                availableProcessedMinFrameDurations.count * 2) <<
+                "The number of minimum frame durations doesn't match the number of "
+                "available sizes. Using fallback values";
+
+        if (availableProcessedSizes.count ==
+                availableProcessedMinFrameDurations.count * 2) {
+            bool gotSize = false;
+            for (size_t i = 0; i < availableProcessedSizes.count; i += 2) {
+                if (availableProcessedSizes.data.i32[i] == mWidth &&
+                        availableProcessedSizes.data.i32[i+1] == mHeight) {
+                    gotSize = true;
+                    minDuration = availableProcessedMinFrameDurations.data.i64[i/2];
+                }
+            }
+            EXPECT_TRUE(gotSize) << "Can't find stream size in list of "
+                    "available sizes: " << mWidth << ", " << mHeight;
+        }
+        if (minDuration == 0) {
+            minDuration = 1 * SEC / 30; // Fall back to 30 fps as minimum duration
+        }
+
+        ASSERT_LT(0, minDuration);
+
+        camera_metadata_ro_entry maxFrameDuration =
+                GetStaticEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION);
+
+        EXPECT_EQ(1u, maxFrameDuration.count) << "No valid maximum frame duration";
+
+        if (maxFrameDuration.count == 1) {
+            maxDuration = maxFrameDuration.data.i64[0];
+        }
+
+        EXPECT_GT(0, maxDuration) << "Max duration is 0 or not given, using fallback";
+
+        if (maxDuration == 0) {
+            maxDuration = 10 * SEC; // Fall back to 10 seconds as max duration
+        }
+
+    }
+    dout << "Available frame duration range for configured stream size: "
+         << minDuration << " - " << maxDuration << " ns" << std::endl;
+
+    // Get environment variables if set
+    const char *expVal = getenv(expEnv);
+    const char *durationVal = getenv(durationEnv);
+    const char *sensitivityVal = getenv(sensitivityEnv);
+
+    bool gotExp = (expVal != NULL);
+    bool gotDuration = (durationVal != NULL);
+    bool gotSensitivity = (sensitivityVal != NULL);
+
+    // All or none must be provided if using override envs
+    ASSERT_TRUE( (gotDuration && gotExp && gotSensitivity) ||
+            (!gotDuration && !gotExp && !gotSensitivity) ) <<
+            "Incomplete set of environment variable overrides provided";
+
+    Vector<int64_t> expList, durationList;
+    Vector<int32_t> sensitivityList;
+    if (gotExp) {
+        ParseList(expVal, expList);
+        ParseList(durationVal, durationList);
+        ParseList(sensitivityVal, sensitivityList);
+
+        ASSERT_TRUE(
+            (expList.size() == durationList.size()) &&
+            (durationList.size() == sensitivityList.size())) <<
+                "Mismatched sizes in env lists, or parse error";
+
+        dout << "Using burst list from environment with " << expList.size() <<
+                " captures" << std::endl;
+    } else {
+        // Create a default set of controls based on the available ranges
+
+        int64_t e;
+        int64_t d;
+        int32_t s;
+
+        // Exposure ramp
+
+        e = minExp;
+        d = minDuration;
+        s = sensitivities[0];
+        while (e < maxExp) {
+            expList.push_back(e);
+            durationList.push_back(d);
+            sensitivityList.push_back(s);
+            e = e * 2;
+        }
+        e = maxExp;
+        expList.push_back(e);
+        durationList.push_back(d);
+        sensitivityList.push_back(s);
+
+        // Duration ramp
+
+        e = 30 * MSEC;
+        d = minDuration;
+        s = sensitivities[0];
+        while (d < maxDuration) {
+            // make sure exposure <= frame duration
+            expList.push_back(e > d ? d : e);
+            durationList.push_back(d);
+            sensitivityList.push_back(s);
+            d = d * 2;
+        }
+
+        // Sensitivity ramp
+
+        e = 30 * MSEC;
+        d = 30 * MSEC;
+        d = d > minDuration ? d : minDuration;
+        for (size_t i = 0; i < sensitivities.size(); i++) {
+            expList.push_back(e);
+            durationList.push_back(d);
+            sensitivityList.push_back(sensitivities[i]);
+        }
+
+        // Constant-EV ramp, duration == exposure
+
+        e = 30 * MSEC; // at ISO 100
+        for (size_t i = 0; i < sensitivities.size(); i++) {
+            int64_t e_adj = e * 100 / sensitivities[i];
+            expList.push_back(e_adj);
+            durationList.push_back(e_adj > minDuration ? e_adj : minDuration);
+            sensitivityList.push_back(sensitivities[i]);
+        }
+
+        dout << "Default burst sequence created with " << expList.size() <<
+                " entries" << std::endl;
+    }
+
+    // Validate the list, but warn only
+    for (size_t i = 0; i < expList.size(); i++) {
+        EXPECT_GE(maxExp, expList[i])
+                << "Capture " << i << " exposure too long: " << expList[i];
+        EXPECT_LE(minExp, expList[i])
+                << "Capture " << i << " exposure too short: " << expList[i];
+        EXPECT_GE(maxDuration, durationList[i])
+                << "Capture " << i << " duration too long: " << durationList[i];
+        EXPECT_LE(minDuration, durationList[i])
+                 << "Capture " << i << " duration too short: "  << durationList[i];
+        bool validSensitivity = false;
+        for (size_t j = 0; j < sensitivities.size(); j++) {
+            if (sensitivityList[i] == sensitivities[j]) {
+                validSensitivity = true;
+                break;
+            }
+        }
+        EXPECT_TRUE(validSensitivity)
+                << "Capture " << i << " sensitivity not in list: " << sensitivityList[i];
+    }
+
+    // Check if debug yuv dumps are requested
+
+    bool dumpFrames = false;
+    {
+        const char *frameDumpVal = getenv(dumpFrameEnv);
+        if (frameDumpVal != NULL) {
+            if (frameDumpVal[0] == '1') dumpFrames = true;
+        }
+    }
+
+    dout << "Dumping YUV frames " <<
+            (dumpFrames ? "enabled, not checking timing" : "disabled") << std::endl;
+
+    // Create a base preview request, turning off all 3A
+    CameraMetadata previewRequest;
+    ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+                                                &previewRequest));
+    {
+        Vector<uint8_t> outputStreamIds;
+        outputStreamIds.push(mStreamId);
+        ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+                                            outputStreamIds));
+
+        // Disable all 3A routines
+        uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+        ASSERT_EQ(OK, previewRequest.update(ANDROID_CONTROL_MODE,
+                                            &cmOff, 1));
+
+        int requestId = 1;
+        ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_ID,
+                                            &requestId, 1));
+    }
+
+    // Submit capture requests
+
+    for (size_t i = 0; i < expList.size(); ++i) {
+        CameraMetadata tmpRequest = previewRequest;
+        ASSERT_EQ(OK, tmpRequest.update(ANDROID_SENSOR_EXPOSURE_TIME,
+                                        &expList[i], 1));
+        ASSERT_EQ(OK, tmpRequest.update(ANDROID_SENSOR_FRAME_DURATION,
+                                        &durationList[i], 1));
+        ASSERT_EQ(OK, tmpRequest.update(ANDROID_SENSOR_SENSITIVITY,
+                                        &sensitivityList[i], 1));
+        ALOGV("Submitting capture %d with exposure %lld, frame duration %lld, sensitivity %d",
+                i, expList[i], durationList[i], sensitivityList[i]);
+        dout << "Capture request " << i <<
+                ": exposure is " << (expList[i]/1e6f) << " ms" <<
+                ", frame duration is " << (durationList[i]/1e6f) << " ms" <<
+                ", sensitivity is " << sensitivityList[i] <<
+                std::endl;
+        ASSERT_EQ(OK, mDevice->capture(tmpRequest));
+    }
+
+    Vector<float> brightnesses;
+    Vector<nsecs_t> captureTimes;
+    brightnesses.setCapacity(expList.size());
+    captureTimes.setCapacity(expList.size());
+
+    // Get each frame (metadata) and then the buffer. Calculate brightness.
+    for (size_t i = 0; i < expList.size(); ++i) {
+
+        ALOGV("Reading request %d", i);
+        dout << "Waiting for capture " << i << ": " <<
+                " exposure " << (expList[i]/1e6f) << " ms," <<
+                " frame duration " << (durationList[i]/1e6f) << " ms," <<
+                " sensitivity " << sensitivityList[i] <<
+                std::endl;
+
+        // Set wait limit based on expected frame duration, or minimum timeout
+        int64_t waitLimit = CAMERA_FRAME_TIMEOUT;
+        if (expList[i] * 2 > waitLimit) waitLimit = expList[i] * 2;
+        if (durationList[i] * 2 > waitLimit) waitLimit = durationList[i] * 2;
+
+        ASSERT_EQ(OK, mDevice->waitForNextFrame(waitLimit));
+        ALOGV("Reading capture request-1 %d", i);
+        CameraMetadata frameMetadata;
+        ASSERT_EQ(OK, mDevice->getNextFrame(&frameMetadata));
+        ALOGV("Reading capture request-2 %d", i);
+
+        ASSERT_EQ(OK, mFrameListener->waitForFrame(CAMERA_FRAME_TIMEOUT));
+        ALOGV("We got the frame now");
+
+        captureTimes.push_back(systemTime());
+
+        CpuConsumer::LockedBuffer imgBuffer;
+        ASSERT_EQ(OK, mCpuConsumer->lockNextBuffer(&imgBuffer));
+
+        int underexposed, overexposed;
+        float avgBrightness = 0;
+        long long brightness = TotalBrightness(imgBuffer, &underexposed,
+                                               &overexposed);
+        int numValidPixels = mWidth * mHeight - (underexposed + overexposed);
+        if (numValidPixels != 0) {
+            avgBrightness = brightness * 1.0f / numValidPixels;
+        } else if (underexposed < overexposed) {
+            avgBrightness = 255;
+        }
+
+        ALOGV("Total brightness for frame %d was %lld (underexposed %d, "
+              "overexposed %d), avg %f", i, brightness, underexposed,
+              overexposed, avgBrightness);
+        dout << "Average brightness (frame " << i << ") was " << avgBrightness
+             << " (underexposed " << underexposed << ", overexposed "
+             << overexposed << ")" << std::endl;
+        brightnesses.push_back(avgBrightness);
+
+        if (i != 0) {
+            float prevEv = static_cast<float>(expList[i - 1]) * sensitivityList[i - 1];
+            float currentEv = static_cast<float>(expList[i]) * sensitivityList[i];
+            float evRatio = (prevEv > currentEv) ? (currentEv / prevEv) :
+                    (prevEv / currentEv);
+            if ( evRatio > EV_MATCH_BOUND ) {
+                EXPECT_LT( fabs(brightnesses[i] - brightnesses[i - 1]),
+                        BRIGHTNESS_MATCH_BOUND) <<
+                        "Capture brightness different from previous, even though "
+                        "they have the same EV value. Ev now: " << currentEv <<
+                        ", previous: " << prevEv << ". Brightness now: " <<
+                        brightnesses[i] << ", previous: " << brightnesses[i-1];
+            }
+            // Only check timing if not saving to disk, since that slows things
+            // down substantially
+            if (!dumpFrames) {
+                nsecs_t timeDelta = captureTimes[i] - captureTimes[i-1];
+                nsecs_t expectedDelta = expList[i] > durationList[i] ?
+                        expList[i] : durationList[i];
+                EXPECT_LT(timeDelta, expectedDelta + DURATION_UPPER_BOUND) <<
+                        "Capture took " << timeDelta << " ns to receive, but expected"
+                        " frame duration was " << expectedDelta << " ns.";
+                EXPECT_GT(timeDelta, expectedDelta - DURATION_LOWER_BOUND) <<
+                        "Capture took " << timeDelta << " ns to receive, but expected"
+                    " frame duration was " << expectedDelta << " ns.";
+                dout << "Time delta from previous frame: " << timeDelta / 1e6 <<
+                        " ms.  Expected " << expectedDelta / 1e6 << " ms" << std::endl;
+            }
+        }
+
+        if (dumpFrames) {
+            String8 dumpName =
+                    String8::format("/data/local/tmp/camera2_test_variable_burst_frame_%03d.yuv", i);
+            dout << "  Writing YUV dump to " << dumpName << std::endl;
+            DumpYuvToFile(dumpName, imgBuffer);
+        }
+
+        ASSERT_EQ(OK, mCpuConsumer->unlockBuffer(imgBuffer));
+    }
+
 }
 
+}
+}
+}
diff --git a/tests/camera2/CameraFrameTests.cpp b/tests/camera2/CameraFrameTests.cpp
index 2b5b546..8445098 100644
--- a/tests/camera2/CameraFrameTests.cpp
+++ b/tests/camera2/CameraFrameTests.cpp
@@ -23,7 +23,7 @@
 #include "hardware/hardware.h"
 #include "hardware/camera2.h"
 
-#include "Camera2Device.h"
+#include "CameraDeviceBase.h"
 #include "utils/StrongPointer.h"
 
 #include <gui/CpuConsumer.h>
@@ -46,7 +46,7 @@
 namespace tests {
 
 static CameraStreamParams STREAM_PARAMETERS = {
-    /*mFormat*/     HAL_PIXEL_FORMAT_YCrCb_420_SP,
+    /*mFormat*/     CAMERA_STREAM_AUTO_CPU_FORMAT,
     /*mHeapCount*/  CAMERA_HEAP_COUNT
 };
 
@@ -139,4 +139,3 @@
 }
 }
 }
-
diff --git a/tests/camera2/CameraMetadataTests.cpp b/tests/camera2/CameraMetadataTests.cpp
index 8cae619..66c4847 100644
--- a/tests/camera2/CameraMetadataTests.cpp
+++ b/tests/camera2/CameraMetadataTests.cpp
@@ -25,7 +25,7 @@
 #include "hardware/hardware.h"
 #include "hardware/camera2.h"
 
-#include "Camera2Device.h"
+#include "CameraDeviceBase.h"
 #include "utils/StrongPointer.h"
 
 #include <gui/CpuConsumer.h>
@@ -142,13 +142,25 @@
         HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
                                        HAL_PIXEL_FORMAT_BLOB)); // JPEG
 
-    EXPECT_TRUE(
-        HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
-                                       HAL_PIXEL_FORMAT_YCrCb_420_SP)); // NV21
+    if (getDeviceVersion() < CAMERA_DEVICE_API_VERSION_3_0) {
+        // HAL2 can support either flexible YUV or YV12 + NV21
+        if (!HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+                        HAL_PIXEL_FORMAT_YCbCr_420_888)) {
 
-    EXPECT_TRUE(
-        HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
-                                       HAL_PIXEL_FORMAT_YV12));
+            EXPECT_TRUE(
+                HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+                        HAL_PIXEL_FORMAT_YCrCb_420_SP)); // NV21
+
+            EXPECT_TRUE(
+                HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+                        HAL_PIXEL_FORMAT_YV12));
+        }
+    } else {
+        // HAL3 must support flexible YUV
+        EXPECT_TRUE(HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+                        HAL_PIXEL_FORMAT_YCbCr_420_888));
+    }
+
 }
 
 TEST_F(CameraMetadataTest, SaneResolutions) {
@@ -156,7 +168,7 @@
 
     // Iff there are listed raw resolutions, the format should be available
     int rawResolutionsCount =
-            GetEntryCountFromStaticTag(HAL_PIXEL_FORMAT_RAW_SENSOR);
+            GetEntryCountFromStaticTag(ANDROID_SCALER_AVAILABLE_RAW_SIZES);
     EXPECT_EQ(rawResolutionsCount > 0,
         HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
                                         HAL_PIXEL_FORMAT_RAW_SENSOR));
diff --git a/tests/camera2/CameraModuleFixture.h b/tests/camera2/CameraModuleFixture.h
index 01e1ad0..ef4a9a5 100644
--- a/tests/camera2/CameraModuleFixture.h
+++ b/tests/camera2/CameraModuleFixture.h
@@ -23,6 +23,7 @@
 #include "hardware/camera2.h"
 
 #include "Camera2Device.h"
+#include "Camera3Device.h"
 #include "camera2_utils.h"
 #include "TestExtensions.h"
 
@@ -82,6 +83,42 @@
         }
     }
 
+    void CreateCamera(int cameraID, /*out*/ sp<CameraDeviceBase> *device) {
+        struct camera_info info;
+        ASSERT_EQ(OK, mModule->get_camera_info(cameraID, &info));
+
+        ASSERT_GE((int)info.device_version, CAMERA_DEVICE_API_VERSION_2_0) <<
+                "Device version too old for camera " << cameraID << ". Version: " <<
+                info.device_version;
+        switch(info.device_version) {
+            case CAMERA_DEVICE_API_VERSION_2_0:
+            case CAMERA_DEVICE_API_VERSION_2_1:
+                *device = new Camera2Device(cameraID);
+                break;
+            case CAMERA_DEVICE_API_VERSION_3_0:
+                *device = new Camera3Device(cameraID);
+                break;
+            default:
+                device->clear();
+                FAIL() << "Device version unknown for camera " << cameraID << ". Version: " <<
+                       info.device_version;
+        }
+
+    }
+
+    int getDeviceVersion() {
+        return getDeviceVersion(mCameraID);
+    }
+
+    int getDeviceVersion(int cameraId, status_t* status = NULL) {
+        camera_info info;
+        status_t res;
+        res = mModule->get_camera_info(cameraId, &info);
+        if (status != NULL) *status = res;
+
+        return info.device_version;
+    }
+
 private:
 
     void SetUpMixin() {
@@ -90,14 +127,12 @@
             EXPECT_LE(0, mCameraID);
             EXPECT_LT(mCameraID, mNumberOfCameras);
 
-            /* HALBUG (Exynos5); crashes if trying to initialize
-               before calling get_camera_info */
-            if (InfoQuirk) {
-                struct camera_info info;
-                ASSERT_EQ(OK, mModule->get_camera_info(mCameraID, &info));
-            }
+            /* HALBUG (Exynos5); crashes if we skip calling get_camera_info
+               before initializing. Need info anyway now. */
 
-            mDevice = new Camera2Device(mCameraID);
+            CreateCamera(mCameraID, &mDevice);
+
+            ASSERT_TRUE(mDevice != NULL) << "Failed to open device " << mCameraID;
             ASSERT_EQ(OK, mDevice->initialize(mModule))
                 << "Failed to initialize device " << mCameraID;
         }
@@ -110,7 +145,7 @@
 protected:
     int mNumberOfCameras;
     camera_module_t *mModule;
-    sp<Camera2Device> mDevice;
+    sp<CameraDeviceBase> mDevice;
 
 private:
     int mCameraID;
diff --git a/tests/camera2/CameraModuleTests.cpp b/tests/camera2/CameraModuleTests.cpp
index fc6fd36..44d3e3b 100644
--- a/tests/camera2/CameraModuleTests.cpp
+++ b/tests/camera2/CameraModuleTests.cpp
@@ -23,7 +23,7 @@
 #include "hardware/hardware.h"
 #include "hardware/camera2.h"
 
-#include "Camera2Device.h"
+#include "CameraDeviceBase.h"
 #include "utils/StrongPointer.h"
 #include "CameraModuleFixture.h"
 
@@ -54,13 +54,6 @@
         return stat;
     }
 
-    int getDeviceVersion(int cameraId, status_t* status) {
-        camera_info info;
-        *status = mModule->get_camera_info(cameraId, &info);
-
-        return info.device_version;
-    }
-
     bool isDeviceVersionHal2(int cameraId, status_t* status) {
         return getDeviceVersion(cameraId, status)
                >= CAMERA_DEVICE_API_VERSION_2_0;
@@ -72,8 +65,7 @@
     TEST_EXTENSION_FORKING_INIT;
 
     for (int i = 0; i < mNumberOfCameras; ++i) {
-        mDevice = new Camera2Device(i);
-
+        CreateCamera(i, &mDevice);
         ASSERT_EQ(OK, initializeDevice(i))
             << "Failed to initialize device " << i;
         mDevice.clear();
@@ -88,6 +80,8 @@
     int idx[] = { -1, mNumberOfCameras, mNumberOfCameras + 1 };
 
     for (unsigned i = 0; i < sizeof(idx)/sizeof(idx[0]); ++i) {
+        // Since the initialization should fail at device open(), it doesn't
+        // matter which version of CameraNDevice is used here
         mDevice = new Camera2Device(idx[i]);
         status_t deviceInitializeCode = initializeDevice(idx[i]);
         EXPECT_NE(OK, deviceInitializeCode);
@@ -136,4 +130,3 @@
 }
 }
 }
-
diff --git a/tests/camera2/CameraStreamFixture.h b/tests/camera2/CameraStreamFixture.h
index c5db7ef..195e764 100644
--- a/tests/camera2/CameraStreamFixture.h
+++ b/tests/camera2/CameraStreamFixture.h
@@ -19,27 +19,50 @@
 
 #include <gtest/gtest.h>
 #include <iostream>
+#include <fstream>
 
 #include <gui/CpuConsumer.h>
 #include <gui/Surface.h>
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
+#include <system/camera_metadata.h>
 
 #include "CameraModuleFixture.h"
 #include "TestExtensions.h"
 
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
 namespace android {
 namespace camera2 {
 namespace tests {
 
+// Format specifier for picking the best format for CPU reading the given device
+// version
+#define CAMERA_STREAM_AUTO_CPU_FORMAT (-1)
+
+struct CameraStreamParams;
+
+void PrintTo(const CameraStreamParams& p, ::std::ostream* os);
+
 struct CameraStreamParams {
     int mFormat;
     int mHeapCount;
+
 };
 
+inline ::std::ostream& operator<<(::std::ostream& os, const CameraStreamParams &p) {
+    PrintTo(p, &os);
+    return os;
+}
+
 inline void PrintTo(const CameraStreamParams& p, ::std::ostream* os) {
+    char fmt[100];
+    camera_metadata_enum_snprint(
+        ANDROID_SCALER_AVAILABLE_FORMATS, p.mFormat, fmt, sizeof(fmt));
+
     *os <<  "{ ";
     *os <<  "Format: 0x"  << std::hex << p.mFormat    << ", ";
+    *os <<  "Format name: " << fmt << ", ";
     *os <<  "HeapCount: " <<             p.mHeapCount;
     *os << " }";
 }
@@ -71,7 +94,7 @@
         CameraModuleFixture::SetUp();
 
         CameraStreamParams p = mParam;
-        sp<Camera2Device> device = mDevice;
+        sp<CameraDeviceBase> device = mDevice;
 
         /* use an arbitrary w,h */
         {
@@ -136,18 +159,21 @@
     };
 
     void CreateStream() {
-        sp<Camera2Device> device = mDevice;
+        sp<CameraDeviceBase> device = mDevice;
         CameraStreamParams p = mParam;
 
-        mCpuConsumer = new CpuConsumer(p.mHeapCount);
+        sp<BufferQueue> bq = new BufferQueue();
+        mCpuConsumer = new CpuConsumer(bq, p.mHeapCount);
         mCpuConsumer->setName(String8("CameraStreamTest::mCpuConsumer"));
 
         mNativeWindow = new Surface(
             mCpuConsumer->getProducerInterface());
 
+        int format = MapAutoFormat(p.mFormat);
+
         ASSERT_EQ(OK,
             device->createStream(mNativeWindow,
-                mWidth, mHeight, p.mFormat, /*size (for jpegs)*/0,
+                mWidth, mHeight, format, /*size (for jpegs)*/0,
                 &mStreamId));
 
         ASSERT_NE(-1, mStreamId);
@@ -161,6 +187,91 @@
         ASSERT_EQ(OK, mDevice->deleteStream(mStreamId));
     }
 
+    int MapAutoFormat(int format) {
+        if (format == CAMERA_STREAM_AUTO_CPU_FORMAT) {
+            if (getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_0) {
+                format = HAL_PIXEL_FORMAT_YCbCr_420_888;
+            } else {
+                format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+            }
+        }
+        return format;
+    }
+
+    void DumpYuvToFile(const String8 &fileName, const CpuConsumer::LockedBuffer &img) {
+        uint8_t *dataCb, *dataCr;
+        uint32_t stride;
+        uint32_t chromaStride;
+        uint32_t chromaStep;
+
+        switch (img.format) {
+            case HAL_PIXEL_FORMAT_YCbCr_420_888:
+                stride = img.stride;
+                chromaStride = img.chromaStride;
+                chromaStep = img.chromaStep;
+                dataCb = img.dataCb;
+                dataCr = img.dataCr;
+                break;
+            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+                stride = img.width;
+                chromaStride = img.width;
+                chromaStep = 2;
+                dataCr = img.data + img.width * img.height;
+                dataCb = dataCr + 1;
+                break;
+            case HAL_PIXEL_FORMAT_YV12:
+                stride = img.stride;
+                chromaStride = ALIGN(img.width / 2, 16);
+                chromaStep = 1;
+                dataCr = img.data + img.stride * img.height;
+                dataCb = dataCr + chromaStride * img.height/2;
+                break;
+            default:
+                ALOGE("Unknown format %d, not dumping", img.format);
+                return;
+        }
+
+        // Write Y
+        FILE *yuvFile = fopen(fileName.string(), "w");
+
+        size_t bytes;
+
+        for (size_t y = 0; y < img.height; ++y) {
+            bytes = fwrite(
+                reinterpret_cast<const char*>(img.data + stride * y),
+                1, img.width, yuvFile);
+            if (bytes != img.width) {
+                ALOGE("Unable to write to file %s", fileName.string());
+                fclose(yuvFile);
+                return;
+            }
+        }
+
+        // Write Cb/Cr
+        uint8_t *src = dataCb;
+        for (int c = 0; c < 2; ++c) {
+            for (size_t y = 0; y < img.height / 2; ++y) {
+                uint8_t *px = src + y * chromaStride;
+                if (chromaStep != 1) {
+                    for (size_t x = 0; x < img.width / 2; ++x) {
+                        fputc(*px, yuvFile);
+                        px += chromaStep;
+                    }
+                } else {
+                    bytes = fwrite(reinterpret_cast<const char*>(px),
+                            1, img.width / 2, yuvFile);
+                    if (bytes != img.width / 2) {
+                        ALOGE("Unable to write to file %s", fileName.string());
+                        fclose(yuvFile);
+                        return;
+                    }
+                }
+            }
+            src = dataCr;
+        }
+        fclose(yuvFile);
+    }
+
     int mWidth;
     int mHeight;
 
diff --git a/tests/camera2/CameraStreamTests.cpp b/tests/camera2/CameraStreamTests.cpp
index 5423a30..164e0e5 100644
--- a/tests/camera2/CameraStreamTests.cpp
+++ b/tests/camera2/CameraStreamTests.cpp
@@ -93,8 +93,8 @@
             std::cerr << "Skipping test "
                       << test_info->test_case_name() << "."
                       << test_info->name()
-                      << " because the format was not available: 0x"
-                      << std::hex << GetParam().mFormat << std::endl;
+                      << " because the format was not available: "
+                      << GetParam() << std::endl;
             return;
         }
     }
@@ -186,4 +186,3 @@
 }
 }
 }
-
diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp
index 0f75070..87f51f0 100644
--- a/tests/camera2/camera2.cpp
+++ b/tests/camera2/camera2.cpp
@@ -92,7 +92,8 @@
                 std::cout << "    Version: 0x" << std::hex <<
                         info.device_version  << std::endl;
             }
-            if (info.device_version >= CAMERA_DEVICE_API_VERSION_2_0) {
+            if (info.device_version >= CAMERA_DEVICE_API_VERSION_2_0 &&
+                    info.device_version < CAMERA_DEVICE_API_VERSION_3_0) {
                 sCameraSupportsHal2[i] = true;
                 ASSERT_TRUE(NULL != info.static_camera_characteristics);
                 IF_ALOGV() {
@@ -181,12 +182,15 @@
         return OK;
     }
 
-    static status_t closeCameraDevice(camera2_device_t *cam_dev) {
+    static status_t closeCameraDevice(camera2_device_t **cam_dev) {
         int res;
+        if (*cam_dev == NULL ) return OK;
+
         ALOGV("Closing camera %p", cam_dev);
 
-        hw_device_t *dev = reinterpret_cast<hw_device_t *>(cam_dev);
+        hw_device_t *dev = reinterpret_cast<hw_device_t *>(*cam_dev);
         res = dev->close(dev);
+        *cam_dev = NULL;
         return res;
     }
 
@@ -195,7 +199,7 @@
         status_t res;
 
         if (mDevice != NULL) {
-            closeCameraDevice(mDevice);
+            closeCameraDevice(&mDevice);
         }
         mDevice = openCameraDevice(id);
         ASSERT_TRUE(NULL != mDevice) << "Failed to open camera device";
@@ -324,7 +328,7 @@
             delete mStreams[i];
         }
         if (mDevice != NULL) {
-            closeCameraDevice(mDevice);
+            closeCameraDevice(&mDevice);
         }
 
         TearDownModule();
@@ -366,7 +370,7 @@
         camera2_device_t *d = openCameraDevice(id);
         ASSERT_TRUE(NULL != d) << "Failed to open camera device";
 
-        res = closeCameraDevice(d);
+        res = closeCameraDevice(&d);
         ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device";
     }
 }
@@ -382,7 +386,8 @@
 
         ASSERT_NO_FATAL_FAILURE(setUpCamera(id));
 
-        sp<CpuConsumer> rawConsumer = new CpuConsumer(1);
+        sp<BufferQueue> bq = new BufferQueue();
+        sp<CpuConsumer> rawConsumer = new CpuConsumer(bq, 1);
         sp<FrameWaiter> rawWaiter = new FrameWaiter();
         rawConsumer->setFrameAvailableListener(rawWaiter);
 
@@ -499,7 +504,7 @@
         ASSERT_EQ(OK, waitUntilDrained());
         ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId));
 
-        res = closeCameraDevice(mDevice);
+        res = closeCameraDevice(&mDevice);
         ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device";
 
     }
@@ -516,7 +521,8 @@
 
         ASSERT_NO_FATAL_FAILURE(setUpCamera(id));
 
-        sp<CpuConsumer> rawConsumer = new CpuConsumer(1);
+        sp<BufferQueue> bq = new BufferQueue();
+        sp<CpuConsumer> rawConsumer = new CpuConsumer(bq, 1);
         sp<FrameWaiter> rawWaiter = new FrameWaiter();
         rawConsumer->setFrameAvailableListener(rawWaiter);
 
@@ -697,7 +703,8 @@
 
         ASSERT_NO_FATAL_FAILURE(setUpCamera(id));
 
-        sp<CpuConsumer> jpegConsumer = new CpuConsumer(1);
+        sp<BufferQueue> bq = new BufferQueue();
+        sp<CpuConsumer> jpegConsumer = new CpuConsumer(bq, 1);
         sp<FrameWaiter> jpegWaiter = new FrameWaiter();
         jpegConsumer->setFrameAvailableListener(jpegWaiter);
 
@@ -802,7 +809,7 @@
         ASSERT_EQ(OK, waitUntilDrained());
         ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId));
 
-        res = closeCameraDevice(mDevice);
+        res = closeCameraDevice(&mDevice);
         ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device";
 
     }