summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2013-11-22 10:35:26 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2013-11-22 10:35:26 -0800
commitbae5cf92cfa9e2867af91057265df7f029f7865e (patch)
tree36c850418ad1433bef13b30be214f4f844a14efa
parentaf822c43cf144a991db49d8c25068d054265ae37 (diff)
parentc9940a2bfe94dbe2ef3bfe5e8692bf4e3cea5ba0 (diff)
downloadlibhardware-bae5cf92cfa9e2867af91057265df7f029f7865e.tar.gz
Merge commit 'c9940a2bfe94dbe2ef3bfe5e8692bf4e3cea5ba0' into HEAD
-rw-r--r--hardware.c4
-rw-r--r--include/hardware/audio.h135
-rw-r--r--include/hardware/audio_effect.h32
-rw-r--r--include/hardware/audio_policy.h10
-rw-r--r--[-rwxr-xr-x]include/hardware/bluetooth.h2
-rw-r--r--include/hardware/bt_gatt_client.h54
-rw-r--r--include/hardware/bt_gatt_types.h6
-rw-r--r--[-rwxr-xr-x]include/hardware/bt_rc.h32
-rw-r--r--include/hardware/camera3.h117
-rw-r--r--include/hardware/camera_common.h89
-rw-r--r--include/hardware/consumerir.h80
-rw-r--r--include/hardware/fused_location.h734
-rw-r--r--include/hardware/gralloc.h3
-rw-r--r--include/hardware/hwcomposer.h40
-rw-r--r--include/hardware/hwcomposer_defs.h7
-rw-r--r--include/hardware/memtrack.h160
-rw-r--r--include/hardware/sensors.h220
-rw-r--r--modules/Android.mk3
-rw-r--r--modules/audio/audio_policy.c11
-rw-r--r--[-rwxr-xr-x]modules/audio_remote_submix/audio_hw.cpp8
-rw-r--r--modules/camera/Android.mk3
-rw-r--r--modules/camera/Camera.cpp528
-rw-r--r--modules/camera/Camera.h40
-rw-r--r--modules/camera/CameraHAL.cpp9
-rw-r--r--modules/camera/Metadata.cpp246
-rw-r--r--modules/camera/Metadata.h79
-rw-r--r--modules/camera/ScopedTrace.h51
-rw-r--r--modules/camera/Stream.cpp177
-rw-r--r--modules/camera/Stream.h79
-rw-r--r--modules/consumerir/Android.mk25
-rw-r--r--modules/consumerir/consumerir.c116
-rw-r--r--modules/gralloc/gralloc.cpp2
-rw-r--r--tests/camera2/Android.mk1
-rw-r--r--tests/camera2/CameraBurstTests.cpp476
-rw-r--r--tests/camera2/CameraFrameTests.cpp7
-rw-r--r--tests/camera2/CameraMetadataTests.cpp14
-rw-r--r--tests/camera2/CameraModuleFixture.h5
-rw-r--r--tests/camera2/CameraModuleTests.cpp24
-rw-r--r--tests/camera2/CameraMultiStreamTests.cpp683
-rw-r--r--tests/camera2/CameraStreamFixture.h84
-rw-r--r--tests/camera2/CameraStreamTests.cpp6
-rw-r--r--tests/camera2/camera2.cpp22
-rw-r--r--tests/camera2/camera2_utils.cpp1
-rw-r--r--tests/hwc/Android.mk14
-rw-r--r--tests/hwc/cnativewindow.c578
-rw-r--r--tests/hwc/test-arrows.c164
-rw-r--r--tests/hwc/util.c236
-rw-r--r--tests/hwc/util.h38
48 files changed, 5273 insertions, 182 deletions
diff --git a/hardware.c b/hardware.c
index 1f831cbc..9651f4c8 100644
--- a/hardware.c
+++ b/hardware.c
@@ -154,6 +154,10 @@ int hw_get_module_by_class(const char *class_id, const char *inst,
if (access(path, R_OK) == 0) break;
} else {
snprintf(path, sizeof(path), "%s/%s.default.so",
+ HAL_LIBRARY_PATH2, name);
+ if (access(path, R_OK) == 0) break;
+
+ snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH1, name);
if (access(path, R_OK) == 0) break;
}
diff --git a/include/hardware/audio.h b/include/hardware/audio.h
index 3a0962ea..6ba2544e 100644
--- a/include/hardware/audio.h
+++ b/include/hardware/audio.h
@@ -67,6 +67,7 @@ __BEGIN_DECLS
#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 @@ __BEGIN_DECLS
* "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 @@ struct audio_stream {
};
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 @@ struct audio_stream_out {
* 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,80 @@ struct audio_stream_out {
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);
+
+ /**
+ * Return a recent count of the number of audio frames presented to an external observer.
+ * This excludes frames which have been written but are still in the pipeline.
+ * The count is not reset to zero when output enters standby.
+ * Also returns the value of CLOCK_MONOTONIC as of this presentation count.
+ * The returned count is expected to be 'recent',
+ * but does not need to be the most recent possible value.
+ * However, the associated time should correspond to whatever count is returned.
+ * Example: assume that N+M frames have been presented, where M is a 'small' number.
+ * Then it is permissible to return N instead of N+M,
+ * and the timestamp should correspond to N rather than N+M.
+ * The terms 'recent' and 'small' are not defined.
+ * They reflect the quality of the implementation.
+ *
+ * 3.0 and higher only.
+ */
+ int (*get_presentation_position)(const struct audio_stream_out *stream,
+ uint64_t *frames, struct timespec *timestamp);
+
};
typedef struct audio_stream_out audio_stream_out_t;
@@ -296,18 +413,14 @@ typedef struct audio_stream_in audio_stream_in_t;
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_effect.h b/include/hardware/audio_effect.h
index 2940b1af..b49d02d6 100644
--- a/include/hardware/audio_effect.h
+++ b/include/hardware/audio_effect.h
@@ -147,6 +147,9 @@ typedef struct effect_descriptor_s {
// | | | 1 requires audio source updates
// | | | 2..3 reserved
// +---------------------------+-----------+-----------------------------------
+// | Effect offload supported | 22 | 0 The effect cannot be offloaded to an audio DSP
+// | | | 1 The effect can be offloaded to an audio DSP
+// +---------------------------+-----------+-----------------------------------
// Insert mode
#define EFFECT_FLAG_TYPE_SHIFT 0
@@ -229,6 +232,14 @@ typedef struct effect_descriptor_s {
#define EFFECT_FLAG_AUDIO_SOURCE_IND (1 << EFFECT_FLAG_AUDIO_SOURCE_SHIFT)
#define EFFECT_FLAG_AUDIO_SOURCE_NONE (0 << EFFECT_FLAG_AUDIO_SOURCE_SHIFT)
+// Effect offload indication
+#define EFFECT_FLAG_OFFLOAD_SHIFT (EFFECT_FLAG_AUDIO_SOURCE_SHIFT + \
+ EFFECT_FLAG_AUDIO_SOURCE_SIZE)
+#define EFFECT_FLAG_OFFLOAD_SIZE 1
+#define EFFECT_FLAG_OFFLOAD_MASK (((1 << EFFECT_FLAG_OFFLOAD_SIZE) -1) \
+ << EFFECT_FLAG_OFFLOAD_SHIFT)
+#define EFFECT_FLAG_OFFLOAD_SUPPORTED (1 << EFFECT_FLAG_OFFLOAD_SHIFT)
+
#define EFFECT_MAKE_API_VERSION(M, m) (((M)<<16) | ((m) & 0xFFFF))
#define EFFECT_API_VERSION_MAJOR(v) ((v)>>16)
#define EFFECT_API_VERSION_MINOR(v) ((m) & 0xFFFF)
@@ -426,6 +437,8 @@ enum effect_command_e {
EFFECT_CMD_GET_FEATURE_CONFIG, // get current feature configuration
EFFECT_CMD_SET_FEATURE_CONFIG, // set current feature configuration
EFFECT_CMD_SET_AUDIO_SOURCE, // set the audio source (see audio.h, audio_source_t)
+ EFFECT_CMD_OFFLOAD, // set if effect thread is an offload one,
+ // send the ioHandle of the effect thread
EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code
};
@@ -732,6 +745,20 @@ enum effect_command_e {
// size: 0
// data: N/A
//==================================================================================================
+// command: EFFECT_CMD_OFFLOAD
+//--------------------------------------------------------------------------------------------------
+// description:
+// 1.indicate if the playback thread the effect is attached to is offloaded or not
+// 2.update the io handle of the playback thread the effect is attached to
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_offload_param_t)
+// data: effect_offload_param_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
// command: EFFECT_CMD_FIRST_PROPRIETARY
//--------------------------------------------------------------------------------------------------
// description:
@@ -868,6 +895,11 @@ typedef struct effect_param_s {
char data[]; // Start of Parameter + Value data
} effect_param_t;
+// structure used by EFFECT_CMD_OFFLOAD command
+typedef struct effect_offload_param_s {
+ bool isOffload; // true if the playback thread the effect is attached to is offloaded
+ int ioHandle; // io handle of the playback thread the effect is attached to
+} effect_offload_param_t;
/////////////////////////////////////////////////
diff --git a/include/hardware/audio_policy.h b/include/hardware/audio_policy.h
index c635ebf5..4e75e02a 100644
--- a/include/hardware/audio_policy.h
+++ b/include/hardware/audio_policy.h
@@ -133,7 +133,8 @@ struct audio_policy {
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 @@ struct audio_policy {
/* 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 @@ struct audio_policy_service_ops {
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 27413327..c00a8f7b 100755..100644
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -451,6 +451,8 @@ typedef struct {
/* 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/bt_gatt_client.h b/include/hardware/bt_gatt_client.h
index 8b49f594..d6b0cb40 100644
--- a/include/hardware/bt_gatt_client.h
+++ b/include/hardware/bt_gatt_client.h
@@ -40,8 +40,8 @@ typedef struct
typedef struct
{
btgatt_srvc_id_t srvc_id;
- btgatt_char_id_t char_id;
- bt_uuid_t descr_id;
+ btgatt_gatt_id_t char_id;
+ btgatt_gatt_id_t descr_id;
btgatt_unformatted_value_t value;
uint16_t value_type;
uint8_t status;
@@ -51,8 +51,8 @@ typedef struct
typedef struct
{
btgatt_srvc_id_t srvc_id;
- btgatt_char_id_t char_id;
- bt_uuid_t descr_id;
+ btgatt_gatt_id_t char_id;
+ btgatt_gatt_id_t descr_id;
uint8_t status;
} btgatt_write_params_t;
@@ -62,7 +62,7 @@ typedef struct
uint8_t value[BTGATT_MAX_ATTR_LEN];
bt_bdaddr_t bda;
btgatt_srvc_id_t srvc_id;
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
uint16_t len;
uint8_t is_notify;
} btgatt_notify_params_t;
@@ -105,13 +105,13 @@ typedef void (*search_result_callback)( int conn_id, btgatt_srvc_id_t *srvc_id);
/** GATT characteristic enumeration result callback */
typedef void (*get_characteristic_callback)(int conn_id, int status,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
int char_prop);
/** GATT descriptor enumeration result callback */
typedef void (*get_descriptor_callback)(int conn_id, int status,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
- bt_uuid_t *descr_id);
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *descr_id);
/** GATT included service enumeration result callback */
typedef void (*get_included_service_callback)(int conn_id, int status,
@@ -120,7 +120,7 @@ typedef void (*get_included_service_callback)(int conn_id, int status,
/** Callback invoked in response to [de]register_for_notification */
typedef void (*register_for_notification_callback)(int conn_id,
int registered, int status, btgatt_srvc_id_t *srvc_id,
- btgatt_char_id_t *char_id);
+ btgatt_gatt_id_t *char_id);
/**
* Remote device notification callback, invoked when a remote device sends
@@ -151,6 +151,11 @@ typedef void (*write_descriptor_callback)(int conn_id, int status,
typedef void (*read_remote_rssi_callback)(int client_if, bt_bdaddr_t* bda,
int rssi, int status);
+/**
+ * Callback indicationg the status of a listen() operation
+ */
+typedef void (*listen_callback)(int status, int server_if);
+
typedef struct {
register_client_callback register_client_cb;
scan_result_callback scan_result_cb;
@@ -169,6 +174,7 @@ typedef struct {
write_descriptor_callback write_descriptor_cb;
execute_write_callback execute_write_cb;
read_remote_rssi_callback read_remote_rssi_cb;
+ listen_callback listen_cb;
} btgatt_client_callbacks_t;
/** Represents the standard BT-GATT client interface. */
@@ -191,6 +197,9 @@ typedef struct {
bt_status_t (*disconnect)( int client_if, const bt_bdaddr_t *bd_addr,
int conn_id);
+ /** Start or stop advertisements to listen for incoming connections */
+ bt_status_t (*listen)(int client_if, bool start);
+
/** Clear the attribute cache for a given device */
bt_status_t (*refresh)( int client_if, const bt_bdaddr_t *bd_addr );
@@ -212,36 +221,36 @@ typedef struct {
* Set start_char_id to NULL to get the first characteristic.
*/
bt_status_t (*get_characteristic)( int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *start_char_id);
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id);
/**
* Enumerate descriptors for a given characteristic.
* Set start_descr_id to NULL to get the first descriptor.
*/
bt_status_t (*get_descriptor)( int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
- bt_uuid_t *start_descr_id);
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *start_descr_id);
/** Read a characteristic on a remote device */
bt_status_t (*read_characteristic)( int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
int auth_req );
/** Write a remote characteristic */
bt_status_t (*write_characteristic)(int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
int write_type, int len, int auth_req,
char* p_value);
/** Read the descriptor for a given characteristic */
bt_status_t (*read_descriptor)(int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
- bt_uuid_t *descr_id, int auth_req);
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *descr_id, int auth_req);
/** Write a remote descriptor for a given characteristic */
bt_status_t (*write_descriptor)( int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
- bt_uuid_t *descr_id, int write_type, int len,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *descr_id, int write_type, int len,
int auth_req, char* p_value);
/** Execute a prepared write operation */
@@ -253,12 +262,12 @@ typedef struct {
*/
bt_status_t (*register_for_notification)( int client_if,
const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
- btgatt_char_id_t *char_id);
+ btgatt_gatt_id_t *char_id);
/** Deregister a previous request for notifications/indications */
bt_status_t (*deregister_for_notification)( int client_if,
const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
- btgatt_char_id_t *char_id);
+ btgatt_gatt_id_t *char_id);
/** Request RSSI for a given remote device */
bt_status_t (*read_remote_rssi)( int client_if, const bt_bdaddr_t *bd_addr);
@@ -266,6 +275,11 @@ typedef struct {
/** Determine the type of the remote device (LE, BR/EDR, Dual-mode) */
int (*get_device_type)( const bt_bdaddr_t *bd_addr );
+ /** Set the advertising data or scan response data */
+ bt_status_t (*set_adv_data)(int server_if, bool set_scan_rsp, bool include_name,
+ bool include_txpower, int min_interval, int max_interval, int appearance,
+ uint16_t manufacturer_len, char* manufacturer_data);
+
/** Test mode interface */
bt_status_t (*test_command)( int command, btgatt_test_params_t* params);
} btgatt_client_interface_t;
diff --git a/include/hardware/bt_gatt_types.h b/include/hardware/bt_gatt_types.h
index fee9bb54..0ac217e8 100644
--- a/include/hardware/bt_gatt_types.h
+++ b/include/hardware/bt_gatt_types.h
@@ -29,17 +29,17 @@ __BEGIN_DECLS
#define BTGATT_SERVICE_TYPE_PRIMARY 0
#define BTGATT_SERVICE_TYPE_SECONDARY 1
-/** GATT Characteristic ID adding instance id tracking to the UUID */
+/** GATT ID adding instance id tracking to the UUID */
typedef struct
{
bt_uuid_t uuid;
uint8_t inst_id;
-} btgatt_char_id_t;
+} btgatt_gatt_id_t;
/** GATT Service ID also identifies the service type (primary/secondary) */
typedef struct
{
- btgatt_char_id_t id;
+ btgatt_gatt_id_t id;
uint8_t is_primary;
} btgatt_srvc_id_t;
diff --git a/include/hardware/bt_rc.h b/include/hardware/bt_rc.h
index 952652e1..d4555437 100755..100644
--- a/include/hardware/bt_rc.h
+++ b/include/hardware/bt_rc.h
@@ -30,6 +30,13 @@ __BEGIN_DECLS
typedef uint8_t btrc_uid_t[BTRC_UID_SIZE];
typedef enum {
+ BTRC_FEAT_NONE = 0x00, /* AVRCP 1.0 */
+ BTRC_FEAT_METADATA = 0x01, /* AVRCP 1.3 */
+ BTRC_FEAT_ABSOLUTE_VOLUME = 0x02, /* Supports TG role and volume sync */
+ BTRC_FEAT_BROWSE = 0x04, /* AVRCP 1.4 and up, with Browsing support */
+} btrc_remote_features_t;
+
+typedef enum {
BTRC_PLAYSTATE_STOPPED = 0x00, /* Stopped */
BTRC_PLAYSTATE_PLAYING = 0x01, /* Playing */
BTRC_PLAYSTATE_PAUSED = 0x02, /* Paused */
@@ -114,6 +121,10 @@ typedef struct {
uint8_t text[BTRC_MAX_ATTR_STR_LEN];
} btrc_element_attr_val_t;
+/** Callback for the controller's supported feautres */
+typedef void (* btrc_remote_features_callback)(bt_bdaddr_t *bd_addr,
+ btrc_remote_features_t features);
+
/** Callback for play status request */
typedef void (* btrc_get_play_status_callback)();
@@ -151,10 +162,20 @@ typedef void (* btrc_get_element_attr_callback) (uint8_t num_attr, btrc_media_at
*/
typedef void (* btrc_register_notification_callback) (btrc_event_id_t event_id, uint32_t param);
+/* AVRCP 1.4 Enhancements */
+/** Callback for volume change on CT
+** volume: Current volume setting on the CT (0-127)
+*/
+typedef void (* btrc_volume_change_callback) (uint8_t volume, uint8_t ctype);
+
+/** Callback for passthrough commands */
+typedef void (* btrc_passthrough_cmd_callback) (int id, int key_state);
+
/** BT-RC callback structure. */
typedef struct {
/** set to sizeof(BtRcCallbacks) */
size_t size;
+ btrc_remote_features_callback remote_features_cb;
btrc_get_play_status_callback get_play_status_cb;
btrc_list_player_app_attr_callback list_player_app_attr_cb;
btrc_list_player_app_values_callback list_player_app_values_cb;
@@ -164,6 +185,8 @@ typedef struct {
btrc_set_player_app_value_callback set_player_app_value_cb;
btrc_get_element_attr_callback get_element_attr_cb;
btrc_register_notification_callback register_notification_cb;
+ btrc_volume_change_callback volume_change_cb;
+ btrc_passthrough_cmd_callback passthrough_cmd_cb;
} btrc_callbacks_t;
/** Represents the standard BT-RC interface. */
@@ -225,6 +248,15 @@ typedef struct {
btrc_notification_type_t type,
btrc_register_notification_t *p_param);
+ /* AVRCP 1.4 enhancements */
+
+ /**Send current volume setting to remote side. Support limited to SetAbsoluteVolume
+ ** This can be enhanced to support Relative Volume (AVRCP 1.0).
+ ** With RelateVolume, we will send VOLUME_UP/VOLUME_DOWN opposed to absolute volume level
+ ** volume: Should be in the range 0-127. bit7 is reseved and cannot be set
+ */
+ bt_status_t (*set_volume)(uint8_t volume);
+
/** Closes the interface. */
void (*cleanup)( void );
} btrc_interface_t;
diff --git a/include/hardware/camera3.h b/include/hardware/camera3.h
index 3a900fc7..afc9d9f1 100644
--- a/include/hardware/camera3.h
+++ b/include/hardware/camera3.h
@@ -21,17 +21,17 @@
#include "camera_common.h"
/**
- * Camera device HAL 3.0 [ CAMERA_DEVICE_API_VERSION_3_0 ]
+ * Camera device HAL 3.1 [ CAMERA_DEVICE_API_VERSION_3_1 ]
*
* EXPERIMENTAL.
*
* Supports the android.hardware.Camera API.
*
* Camera devices that support this version of the HAL must return
- * CAMERA_DEVICE_API_VERSION_3_0 in camera_device_t.common.version and in
+ * CAMERA_DEVICE_API_VERSION_3_1 in camera_device_t.common.version and in
* camera_info_t.device_version (from camera_module_t.get_camera_info).
*
- * Camera modules that may contain version 3.0 devices must implement at least
+ * Camera modules that may contain version 3.1 devices must implement at least
* version 2.0 of the camera module interface (as defined by
* camera_module_t.common.module_api_version).
*
@@ -82,6 +82,12 @@
* management. Bidirectional streams replace STREAM_FROM_STREAM construct.
*
* - Limited mode semantics for older/limited hardware devices.
+ *
+ * 3.1: Minor revision of expanded-capability HAL:
+ *
+ * - configure_streams passes consumer usage flags to the HAL.
+ *
+ * - flush call to drop all in-flight requests/buffers as fast as possible.
*/
/**
@@ -392,6 +398,10 @@
* well focused. The lens is not moving. The HAL may spontaneously leave
* this state.
*
+ * AF_STATE_PASSIVE_UNFOCUSED: A continuous focus algorithm believes it is
+ * not well focused. The lens is not moving. The HAL may spontaneously
+ * leave this state.
+ *
* AF_STATE_ACTIVE_SCAN: A scan triggered by the user is underway.
*
* AF_STATE_FOCUSED_LOCKED: The AF algorithm believes it is focused. The
@@ -565,10 +575,16 @@
*
* S4.5. AF state machines
*
+ * when enabling AF or changing AF mode
+ *| state | trans. cause | new state | notes |
+ *+--------------------+---------------+--------------------+------------------+
+ *| Any | AF mode change| INACTIVE | |
+ *+--------------------+---------------+--------------------+------------------+
+ *
* mode = AF_MODE_OFF or AF_MODE_EDOF
*| state | trans. cause | new state | notes |
*+--------------------+---------------+--------------------+------------------+
- *| INACTIVE | | | AF is disabled |
+ *| INACTIVE | | INACTIVE | Never changes |
*+--------------------+---------------+--------------------+------------------+
*
* mode = AF_MODE_AUTO or AF_MODE_MACRO
@@ -611,6 +627,9 @@
*| PASSIVE_SCAN | HAL completes | PASSIVE_FOCUSED | End AF scan |
*| | current scan | | Lens now locked |
*+--------------------+---------------+--------------------+------------------+
+ *| PASSIVE_SCAN | HAL fails | PASSIVE_UNFOCUSED | End AF scan |
+ *| | current scan | | Lens now locked |
+ *+--------------------+---------------+--------------------+------------------+
*| PASSIVE_SCAN | AF_TRIGGER | FOCUSED_LOCKED | Immediate trans. |
*| | | | if focus is good |
*| | | | Lens now locked |
@@ -626,12 +645,13 @@
*| PASSIVE_FOCUSED | HAL initiates | PASSIVE_SCAN | Start AF scan |
*| | new scan | | Lens now moving |
*+--------------------+---------------+--------------------+------------------+
+ *| PASSIVE_UNFOCUSED | HAL initiates | PASSIVE_SCAN | Start AF scan |
+ *| | new scan | | Lens now moving |
+ *+--------------------+---------------+--------------------+------------------+
*| PASSIVE_FOCUSED | AF_TRIGGER | FOCUSED_LOCKED | Immediate trans. |
- *| | | | if focus is good |
*| | | | Lens now locked |
*+--------------------+---------------+--------------------+------------------+
- *| PASSIVE_FOCUSED | AF_TRIGGER | NOT_FOCUSED_LOCKED | Immediate trans. |
- *| | | | if focus is bad |
+ *| PASSIVE_UNFOCUSED | AF_TRIGGER | NOT_FOCUSED_LOCKED | Immediate trans. |
*| | | | Lens now locked |
*+--------------------+---------------+--------------------+------------------+
*| FOCUSED_LOCKED | AF_TRIGGER | FOCUSED_LOCKED | No effect |
@@ -655,6 +675,9 @@
*| PASSIVE_SCAN | HAL completes | PASSIVE_FOCUSED | End AF scan |
*| | current scan | | Lens now locked |
*+--------------------+---------------+--------------------+------------------+
+ *| PASSIVE_SCAN | HAL fails | PASSIVE_UNFOCUSED | End AF scan |
+ *| | current scan | | Lens now locked |
+ *+--------------------+---------------+--------------------+------------------+
*| PASSIVE_SCAN | AF_TRIGGER | FOCUSED_LOCKED | Eventual trans. |
*| | | | once focus good |
*| | | | Lens now locked |
@@ -670,12 +693,13 @@
*| PASSIVE_FOCUSED | HAL initiates | PASSIVE_SCAN | Start AF scan |
*| | new scan | | Lens now moving |
*+--------------------+---------------+--------------------+------------------+
+ *| PASSIVE_UNFOCUSED | HAL initiates | PASSIVE_SCAN | Start AF scan |
+ *| | new scan | | Lens now moving |
+ *+--------------------+---------------+--------------------+------------------+
*| PASSIVE_FOCUSED | AF_TRIGGER | FOCUSED_LOCKED | Immediate trans. |
- *| | | | if focus is good |
*| | | | Lens now locked |
*+--------------------+---------------+--------------------+------------------+
- *| PASSIVE_FOCUSED | AF_TRIGGER | NOT_FOCUSED_LOCKED | Immediate trans. |
- *| | | | if focus is bad |
+ *| PASSIVE_UNFOCUSED | AF_TRIGGER | NOT_FOCUSED_LOCKED | Immediate trans. |
*| | | | Lens now locked |
*+--------------------+---------------+--------------------+------------------+
*| FOCUSED_LOCKED | AF_TRIGGER | FOCUSED_LOCKED | No effect |
@@ -693,10 +717,16 @@
* FLASH_REQUIRED and PRECAPTURE states. So rows below that refer to those two
* states should be ignored for the AWB state machine.
*
+ * when enabling AE/AWB or changing AE/AWB mode
+ *| state | trans. cause | new state | notes |
+ *+--------------------+---------------+--------------------+------------------+
+ *| Any | mode change | INACTIVE | |
+ *+--------------------+---------------+--------------------+------------------+
+ *
* mode = AE_MODE_OFF / AWB mode not AUTO
*| state | trans. cause | new state | notes |
*+--------------------+---------------+--------------------+------------------+
- *| INACTIVE | | | AE/AWB disabled |
+ *| INACTIVE | | INACTIVE | AE/AWB disabled |
*+--------------------+---------------+--------------------+------------------+
*
* mode = AE_MODE_ON_* / AWB_MODE_AUTO
@@ -1041,6 +1071,9 @@ typedef enum camera3_stream_type {
* remain valid as if configure_streams() had not been called.
*
* The endpoint of the stream is not visible to the camera HAL device.
+ * In DEVICE_API_VERSION_3_1, this was changed to share consumer usage flags
+ * on streams where the camera is a producer (OUTPUT and BIDIRECTIONAL stream
+ * types) see the usage field below.
*/
typedef struct camera3_stream {
@@ -1092,6 +1125,25 @@ typedef struct camera3_stream {
* the producer and the consumer will be combined together and then passed
* to the platform gralloc HAL module for allocating the gralloc buffers for
* each stream.
+ *
+ * Version information:
+ *
+ * == CAMERA_DEVICE_API_VERSION_3_0:
+ *
+ * No initial value guaranteed when passed via configure_streams().
+ * HAL may not use this field as input, and must write over this field
+ * with its usage flags.
+ *
+ * >= CAMERA_DEVICE_API_VERSION_3_1:
+ *
+ * For stream_type OUTPUT and BIDIRECTIONAL, when passed via
+ * configure_streams(), the initial value of this is the consumer's
+ * usage flags. The HAL may use these consumer flags to decide stream
+ * configuration.
+ * For stream_type INPUT, when passed via configure_streams(), the initial
+ * value of this is 0.
+ * For all streams passed via configure_streams(), the HAL must write
+ * over this field with its usage flags.
*/
uint32_t usage;
@@ -2035,6 +2087,49 @@ typedef struct camera3_device_ops {
*/
void (*dump)(const struct camera3_device *, int fd);
+ /**
+ * flush:
+ *
+ * Flush all currently in-process captures and all buffers in the pipeline
+ * on the given device. The framework will use this to dump all state as
+ * quickly as possible in order to prepare for a configure_streams() call.
+ *
+ * No buffers are required to be successfully returned, so every buffer
+ * held at the time of flush() (whether sucessfully filled or not) may be
+ * returned with CAMERA3_BUFFER_STATUS_ERROR. Note the HAL is still allowed
+ * to return valid (STATUS_OK) buffers during this call, provided they are
+ * succesfully filled.
+ *
+ * All requests currently in the HAL are expected to be returned as soon as
+ * possible. Not-in-process requests should return errors immediately. Any
+ * interruptible hardware blocks should be stopped, and any uninterruptible
+ * blocks should be waited on.
+ *
+ * flush() should only return when there are no more outstanding buffers or
+ * requests left in the HAL. The framework may call configure_streams (as
+ * the HAL state is now quiesced) or may issue new requests.
+ *
+ * A flush() call should only take 100ms or less. The maximum time it can
+ * take is 1 second.
+ *
+ * Version information:
+ *
+ * only available if device version >= CAMERA_DEVICE_API_VERSION_3_1.
+ *
+ * Return values:
+ *
+ * 0: On a successful flush of the camera HAL.
+ *
+ * -EINVAL: If the input is malformed (the device is not valid).
+ *
+ * -ENODEV: If the camera device has encountered a serious error. After this
+ * error is returned, only the close() method can be successfully
+ * called by the framework.
+ */
+ int (*flush)(const struct camera3_device *);
+
+ /* reserved for future use */
+ void *reserved[8];
} camera3_device_ops_t;
/**********************************************************************
diff --git a/include/hardware/camera_common.h b/include/hardware/camera_common.h
index 62c57402..3a1233f6 100644
--- a/include/hardware/camera_common.h
+++ b/include/hardware/camera_common.h
@@ -67,6 +67,13 @@ __BEGIN_DECLS
* framework from the camera HAL module, which is used to notify the framework
* about changes to the camera module state. Modules that provide a valid
* set_callbacks() method must report at least this version number.
+ *
+ *******************************************************************************
+ * Version: 2.2 [CAMERA_MODULE_API_VERSION_2_2]
+ *
+ * This camera module version adds vendor tag support from the module, and
+ * deprecates the old vendor_tag_query_ops that were previously only
+ * accessible with a device open.
*/
/**
@@ -80,8 +87,9 @@ __BEGIN_DECLS
#define CAMERA_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
#define CAMERA_MODULE_API_VERSION_2_0 HARDWARE_MODULE_API_VERSION(2, 0)
#define CAMERA_MODULE_API_VERSION_2_1 HARDWARE_MODULE_API_VERSION(2, 1)
+#define CAMERA_MODULE_API_VERSION_2_2 HARDWARE_MODULE_API_VERSION(2, 2)
-#define CAMERA_MODULE_API_VERSION_CURRENT CAMERA_MODULE_API_VERSION_2_1
+#define CAMERA_MODULE_API_VERSION_CURRENT CAMERA_MODULE_API_VERSION_2_2
/**
* All device versions <= HARDWARE_DEVICE_API_VERSION(1, 0xFF) must be treated
@@ -91,6 +99,7 @@ __BEGIN_DECLS
#define CAMERA_DEVICE_API_VERSION_2_0 HARDWARE_DEVICE_API_VERSION(2, 0)
#define CAMERA_DEVICE_API_VERSION_2_1 HARDWARE_DEVICE_API_VERSION(2, 1)
#define CAMERA_DEVICE_API_VERSION_3_0 HARDWARE_DEVICE_API_VERSION(3, 0)
+#define CAMERA_DEVICE_API_VERSION_3_1 HARDWARE_DEVICE_API_VERSION(3, 1)
// Device version 2.x is outdated; device version 3.0 is experimental
#define CAMERA_DEVICE_API_VERSION_CURRENT CAMERA_DEVICE_API_VERSION_1_0
@@ -242,6 +251,65 @@ typedef struct camera_module_callbacks {
} camera_module_callbacks_t;
+/**
+ * Set up vendor-specific tag query methods. These are needed to properly query
+ * entries with vendor-specified tags, potentially returned by get_camera_info.
+ *
+ * This should be used in place of vendor_tag_query_ops, which are deprecated.
+ */
+typedef struct vendor_tag_ops vendor_tag_ops_t;
+struct vendor_tag_ops {
+ /**
+ * Get the number of vendor tags supported on this platform. Used to
+ * calculate the size of buffer needed for holding the array of all tags
+ * returned by get_all_tags().
+ */
+ int (*get_tag_count)(const vendor_tag_ops_t *v);
+
+ /**
+ * Fill an array with all the supported vendor tags on this platform.
+ * get_tag_count() returns the number of tags supported, and
+ * tag_array will be allocated with enough space to hold all of the tags.
+ */
+ void (*get_all_tags)(const vendor_tag_ops_t *v, uint32_t *tag_array);
+
+ /**
+ * Get vendor section name for a vendor-specified entry tag. Only called for
+ * vendor-defined tags. The section name must start with the name of the
+ * vendor in the Java package style. For example, CameraZoom Inc. must
+ * prefix their sections with "com.camerazoom." Must return NULL if the tag
+ * is outside the bounds of vendor-defined sections.
+ *
+ * There may be different vendor-defined tag sections, for example the
+ * phone maker, the chipset maker, and the camera module maker may each
+ * have their own "com.vendor."-prefixed section.
+ *
+ * The memory pointed to by the return value must remain valid for the
+ * lifetime that the module is loaded, and is owned by the module.
+ */
+ const char *(*get_section_name)(const vendor_tag_ops_t *v, uint32_t tag);
+
+ /**
+ * Get tag name for a vendor-specified entry tag. Only called for
+ * vendor-defined tags. Must return NULL if the it is not a vendor-defined
+ * tag.
+ *
+ * The memory pointed to by the return value must remain valid for the
+ * lifetime that the module is loaded, and is owned by the module.
+ */
+ const char *(*get_tag_name)(const vendor_tag_ops_t *v, uint32_t tag);
+
+ /**
+ * Get tag type for a vendor-specified entry tag. Only called for tags >=
+ * 0x80000000. Must return -1 if the tag is outside the bounds of
+ * vendor-defined sections.
+ */
+ int (*get_tag_type)(const vendor_tag_ops_t *v, uint32_t tag);
+
+ /* reserved for future use */
+ void* reserved[8];
+};
+
typedef struct camera_module {
hw_module_t common;
@@ -290,6 +358,25 @@ typedef struct camera_module {
*/
int (*set_callbacks)(const camera_module_callbacks_t *callbacks);
+ /**
+ * get_vendor_tag_ops:
+ *
+ * Get methods to query for vendor extension metadata tag information. The
+ * HAL should fill in all the vendor tag operation methods, or leave ops
+ * unchanged if no vendor tags are defined.
+ *
+ * Version information (based on camera_module_t.common.module_api_version):
+ *
+ * CAMERA_MODULE_API_VERSION_1_x/2_0/2_1:
+ * Not provided by HAL module. Framework may not call this function.
+ *
+ * CAMERA_MODULE_API_VERSION_2_2:
+ * Valid to be called by the framework.
+ */
+ void (*get_vendor_tag_ops)(vendor_tag_ops_t* ops);
+
+ /* reserved for future use */
+ void* reserved[8];
} camera_module_t;
__END_DECLS
diff --git a/include/hardware/consumerir.h b/include/hardware/consumerir.h
new file mode 100644
index 00000000..5adf6be5
--- /dev/null
+++ b/include/hardware/consumerir.h
@@ -0,0 +1,80 @@
+/*
+ * 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 ANDROID_INCLUDE_HARDWARE_CONSUMERIR_H
+#define ANDROID_INCLUDE_HARDWARE_CONSUMERIR_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer_defs.h>
+
+#define CONSUMERIR_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
+#define CONSUMERIR_HARDWARE_MODULE_ID "consumerir"
+#define CONSUMERIR_TRANSMITTER "transmitter"
+
+typedef struct consumerir_freq_range {
+ int min;
+ int max;
+} consumerir_freq_range_t;
+
+typedef struct consumerir_module {
+ struct hw_module_t common;
+} consumerir_module_t;
+
+typedef struct consumerir_device {
+ struct hw_device_t common;
+
+ /*
+ * (*transmit)() is called to by the ConsumerIrService to send an IR pattern
+ * at a given carrier_freq.
+ *
+ * The pattern is alternating series of carrier on and off periods measured in
+ * microseconds. The carrier should be turned off at the end of a transmit
+ * even if there are and odd number of entries in the pattern array.
+ *
+ * This call should return when the transmit is complete or encounters an error.
+ *
+ * returns: 0 on success. A negative error code on error.
+ */
+ int (*transmit)(struct consumerir_device *dev, int carrier_freq,
+ const int pattern[], int pattern_len);
+
+ /*
+ * (*get_num_carrier_freqs)() is called by the ConsumerIrService to get the
+ * number of carrier freqs to allocate space for, which is then filled by
+ * a subsequent call to (*get_carrier_freqs)().
+ *
+ * returns: the number of ranges on success. A negative error code on error.
+ */
+ int (*get_num_carrier_freqs)(struct consumerir_device *dev);
+
+ /*
+ * (*get_carrier_freqs)() is called by the ConsumerIrService to enumerate
+ * which frequencies the IR transmitter supports. The HAL implementation
+ * should fill an array of consumerir_freq_range structs with the
+ * appropriate values for the transmitter, up to len elements.
+ *
+ * returns: the number of ranges on success. A negative error code on error.
+ */
+ int (*get_carrier_freqs)(struct consumerir_device *dev,
+ size_t len, consumerir_freq_range_t *ranges);
+
+ /* Reserved for future use. Must be NULL. */
+ void* reserved[8 - 3];
+} consumerir_device_t;
+
+#endif /* ANDROID_INCLUDE_HARDWARE_CONSUMERIR_H */
diff --git a/include/hardware/fused_location.h b/include/hardware/fused_location.h
new file mode 100644
index 00000000..5c7821c8
--- /dev/null
+++ b/include/hardware/fused_location.h
@@ -0,0 +1,734 @@
+/*
+ * 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 ANDROID_INCLUDE_HARDWARE_FUSED_LOCATION_H
+#define ANDROID_INCLUDE_HARDWARE_FUSED_LOCATION_H
+
+#include <hardware/hardware.h>
+
+
+/**
+ * This header file defines the interface of the Fused Location Provider.
+ * Fused Location Provider is designed to fuse data from various sources
+ * like GPS, Wifi, Cell, Sensors, Bluetooth etc to provide a fused location to the
+ * upper layers. The advantage of doing fusion in hardware is power savings.
+ * The goal is to do this without waking up the AP to get additional data.
+ * The software implementation of FLP will decide when to use
+ * the hardware fused location. Other location features like geofencing will
+ * also be implemented using fusion in hardware.
+ */
+__BEGIN_DECLS
+
+#define FLP_HEADER_VERSION 1
+#define FLP_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
+#define FLP_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION_2(0, 1, FLP_HEADER_VERSION)
+
+/**
+ * The id of this module
+ */
+#define FUSED_LOCATION_HARDWARE_MODULE_ID "flp"
+
+/**
+ * Name for the FLP location interface
+ */
+#define FLP_LOCATION_INTERFACE "flp_location"
+
+/**
+ * Name for the FLP location interface
+ */
+#define FLP_DIAGNOSTIC_INTERFACE "flp_diagnostic"
+
+/**
+ * Name for the FLP_Geofencing interface.
+ */
+#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.
+ */
+#define FLP_TECH_MASK_GNSS (1U<<0)
+#define FLP_TECH_MASK_WIFI (1U<<1)
+#define FLP_TECH_MASK_SENSORS (1U<<2)
+#define FLP_TECH_MASK_CELL (1U<<3)
+#define FLP_TECH_MASK_BLUETOOTH (1U<<4)
+
+/**
+ * This constant is used with the batched locations
+ * APIs. Batching is mandatory when FLP implementation
+ * is supported. If the flag is set, the hardware implementation
+ * will wake up the application processor when the FIFO is full,
+ * If the flag is not set, the hardware implementation will drop
+ * the oldest data when the FIFO is full.
+ */
+#define FLP_BATCH_WAKEUP_ON_FIFO_FULL 0x0000001
+
+/**
+ * While batching, the implementation should not call the
+ * flp_location_callback on every location fix. However,
+ * sometimes in high power mode, the system might need
+ * a location callback every single time the location
+ * 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
+
+/** Flags to indicate which values are valid in a FlpLocation. */
+typedef uint16_t FlpLocationFlags;
+
+// IMPORTANT: Note that the following values must match
+// constants in the corresponding java file.
+
+/** FlpLocation has valid latitude and longitude. */
+#define FLP_LOCATION_HAS_LAT_LONG (1U<<0)
+/** FlpLocation has valid altitude. */
+#define FLP_LOCATION_HAS_ALTITUDE (1U<<1)
+/** FlpLocation has valid speed. */
+#define FLP_LOCATION_HAS_SPEED (1U<<2)
+/** FlpLocation has valid bearing. */
+#define FLP_LOCATION_HAS_BEARING (1U<<4)
+/** FlpLocation has valid accuracy. */
+#define FLP_LOCATION_HAS_ACCURACY (1U<<8)
+
+
+typedef int64_t FlpUtcTime;
+
+/** Represents a location. */
+typedef struct {
+ /** set to sizeof(FlpLocation) */
+ size_t size;
+
+ /** Flags associated with the location object. */
+ FlpLocationFlags flags;
+
+ /** Represents latitude in degrees. */
+ double latitude;
+
+ /** Represents longitude in degrees. */
+ double longitude;
+
+ /**
+ * Represents altitude in meters above the WGS 84 reference
+ * ellipsoid. */
+ double altitude;
+
+ /** Represents speed in meters per second. */
+ float speed;
+
+ /** Represents heading in degrees. */
+ float bearing;
+
+ /** Represents expected accuracy in meters. */
+ float accuracy;
+
+ /** Timestamp for the location fix. */
+ FlpUtcTime timestamp;
+
+ /** Sources used, will be Bitwise OR of the FLP_TECH_MASK bits. */
+ uint32_t sources_used;
+} FlpLocation;
+
+typedef enum {
+ ASSOCIATE_JVM,
+ DISASSOCIATE_JVM,
+} ThreadEvent;
+
+/**
+ * Callback with location information.
+ * 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.
+ */
+typedef void (*flp_location_callback)(int32_t num_locations, FlpLocation** location);
+
+/**
+ * Callback utility for acquiring a wakelock.
+ * This can be used to prevent the CPU from suspending while handling FLP events.
+ */
+typedef void (*flp_acquire_wakelock)();
+
+/**
+ * Callback utility for releasing the FLP wakelock.
+ */
+typedef void (*flp_release_wakelock)();
+
+/**
+ * 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 int (*flp_set_thread_event)(ThreadEvent event);
+
+/** FLP callback structure. */
+typedef struct {
+ /** set to sizeof(FlpCallbacks) */
+ size_t size;
+ flp_location_callback location_cb;
+ flp_acquire_wakelock acquire_wakelock_cb;
+ flp_release_wakelock release_wakelock_cb;
+ flp_set_thread_event set_thread_event_cb;
+} FlpCallbacks;
+
+
+/** Options with the batching FLP APIs */
+typedef struct {
+ /**
+ * 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;
+
+ /** Bitwise OR of the FLP_TECH_MASKS to use */
+ uint32_t sources_to_use;
+
+ /**
+ * FLP_BATCH_WAKEUP_ON_FIFO_FULL - If set the hardware
+ * will wake up the AP when the buffer is full. If not set, the
+ * hardware will drop the oldest location object.
+ *
+ * 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. 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.
+ */
+ uint32_t flags;
+
+ /**
+ * Frequency with which location needs to be batched in nano
+ * seconds.
+ */
+ int64_t period_ns;
+} FlpBatchOptions;
+
+#define FLP_RESULT_SUCCESS 0
+#define FLP_RESULT_ERROR -1
+#define FLP_RESULT_INSUFFICIENT_MEMORY -2
+#define FLP_RESULT_TOO_MANY_GEOFENCES -3
+#define FLP_RESULT_ID_EXISTS -4
+#define FLP_RESULT_ID_UNKNOWN -5
+#define FLP_RESULT_INVALID_GEOFENCE_TRANSITION -6
+
+/**
+ * Represents the standard FLP interface.
+ */
+typedef struct {
+ /**
+ * set to sizeof(FlpLocationInterface)
+ */
+ size_t size;
+
+ /**
+ * Opens the interface and provides the callback routines
+ * to the implemenation of this interface.
+ */
+ int (*init)(FlpCallbacks* callbacks );
+
+ /**
+ * 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.
+ */
+ int (*get_batch_size)();
+
+ /**
+ * Start batching locations. This API is primarily used when the AP is
+ * asleep and the device can batch locations in the hardware.
+ * flp_location_callback is used to return the locations. When the buffer
+ * is full and FLP_BATCH_WAKEUP_ON_FIFO_FULL is used, the AP is woken up.
+ * When the buffer is full and FLP_BATCH_WAKEUP_ON_FIFO_FULL is not set,
+ * the oldest location object is dropped. In this case the AP will not be
+ * woken up. The upper layer will use get_batched_location
+ * API to explicitly ask for the location.
+ * If FLP_BATCH_CALLBACK_ON_LOCATION_FIX is set, the implementation
+ * will call the flp_location_callback every single time there is a location
+ * fix. This overrides FLP_BATCH_WAKEUP_ON_FIFO_FULL flag setting.
+ * It's the responsibility of the upper layers (caller) to switch
+ * it off, if it knows that the AP might go to sleep. This is useful
+ * for nagivational applications when the system is in high power mode.
+ * Parameters:
+ * id - Id for the request.
+ * options - See FlpBatchOptions struct definition.
+ * Return value:
+ * FLP_RESULT_SUCCESS on success, FLP_RESULT_INSUFFICIENT_MEMORY,
+ * FLP_RESULT_ID_EXISTS, FLP_RESULT_ERROR on failure.
+ */
+ int (*start_batching)(int id, FlpBatchOptions* options);
+
+ /**
+ * Update FlpBatchOptions associated with a batching request.
+ * When a batching operation is in progress and a batching option
+ * such as FLP_BATCH_WAKEUP_ON_FIFO_FULL needs to be updated, this API
+ * will be used. For instance, this can happen when the AP is awake and
+ * the maps application is being used.
+ * Parameters:
+ * id - Id of an existing batch request.
+ * new_options - Updated FlpBatchOptions
+ * Return value:
+ * FLP_RESULT_SUCCESS on success, FLP_RESULT_ID_UNKNOWN,
+ * FLP_RESULT_ERROR on error.
+ */
+ int (*update_batching_options)(int id, FlpBatchOptions* new_options);
+
+ /**
+ * Stop batching.
+ * Parameters:
+ * id - Id for the request.
+ * Return Value:
+ * FLP_RESULT_SUCCESS on success, FLP_RESULT_ID_UNKNOWN or
+ * FLP_RESULT_ERROR on failure.
+ */
+ int (*stop_batching)(int id);
+
+ /**
+ * Closes the interface. If any batch operations are in progress,
+ * they should be stopped.
+ */
+ void (*cleanup)();
+
+ /**
+ * Get the fused location that was batched.
+ * flp_location_callback is used to return the location. The location object
+ * is dropped from the buffer only when the buffer is full. Do not remove it
+ * from the buffer just because it has been returned using the callback.
+ * In other words, when there is no new location object, two calls to
+ * get_batched_location(1) should return the same location object.
+ * Parameters:
+ * last_n_locations - Number of locations to get. This can be one or many.
+ * If the last_n_locations is 1, you get the latest location known to the
+ * hardware.
+ */
+ void (*get_batched_location)(int last_n_locations);
+
+ /**
+ * Injects current location from another location provider
+ * latitude and longitude are measured in degrees
+ * expected accuracy is measured in meters
+ * Parameters:
+ * location - The location object being injected.
+ * Return value: FLP_RESULT_SUCCESS or FLP_RESULT_ERROR.
+ */
+ int (*inject_location)(FlpLocation* location);
+
+ /**
+ * Get a pointer to extension information.
+ */
+ const void* (*get_extension)(const char* name);
+} FlpLocationInterface;
+
+struct flp_device_t {
+ struct hw_device_t common;
+
+ /**
+ * Get a handle to the FLP Interface.
+ */
+ const FlpLocationInterface* (*get_flp_interface)(struct flp_device_t* dev);
+};
+
+/**
+ * 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(FlpDiagnosticCallbacks) */
+ size_t size;
+
+ 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(FlpDiagnosticInterface) */
+ size_t size;
+
+ /**
+ * Opens the diagnostic interface and provides the callback routines
+ * to the implemenation of this interface.
+ */
+ 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 FLP_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_device_context)(uint32_t enabledMask);
+} FlpDeviceContextInterface;
+
+
+/**
+ * There are 3 states associated with a Geofence: Inside, Outside, Unknown.
+ * There are 3 transitions: ENTERED, EXITED, UNCERTAIN.
+ *
+ * An example state diagram with confidence level: 95% and Unknown time limit
+ * set as 30 secs is shown below. (confidence level and Unknown time limit are
+ * explained latter)
+ * ____________________________
+ * | Unknown (30 secs) |
+ * """"""""""""""""""""""""""""
+ * ^ | | ^
+ * UNCERTAIN| |ENTERED EXITED| |UNCERTAIN
+ * | v v |
+ * ________ EXITED _________
+ * | Inside | -----------> | Outside |
+ * | | <----------- | |
+ * """""""" ENTERED """""""""
+ *
+ * Inside state: We are 95% confident that the user is inside the geofence.
+ * Outside state: We are 95% confident that the user is outside the geofence
+ * Unknown state: Rest of the time.
+ *
+ * The Unknown state is better explained with an example:
+ *
+ * __________
+ * | c|
+ * | ___ | _______
+ * | |a| | | b |
+ * | """ | """""""
+ * | |
+ * """"""""""
+ * In the diagram above, "a" and "b" are 2 geofences and "c" is the accuracy
+ * circle reported by the FLP subsystem. Now with regard to "b", the system is
+ * confident that the user is outside. But with regard to "a" is not confident
+ * whether it is inside or outside the geofence. If the accuracy remains the
+ * same for a sufficient period of time, the UNCERTAIN transition would be
+ * triggered with the state set to Unknown. If the accuracy improves later, an
+ * appropriate transition should be triggered. This "sufficient period of time"
+ * is defined by the parameter in the add_geofence_area API.
+ * In other words, Unknown state can be interpreted as a state in which the
+ * FLP subsystem isn't confident enough that the user is either inside or
+ * outside the Geofence. It moves to Unknown state only after the expiry of the
+ * timeout.
+ *
+ * The geofence callback needs to be triggered for the ENTERED and EXITED
+ * transitions, when the FLP system is confident that the user has entered
+ * (Inside state) or exited (Outside state) the Geofence. An implementation
+ * which uses a value of 95% as the confidence is recommended. The callback
+ * should be triggered only for the transitions requested by the
+ * add_geofence_area call.
+ *
+ * Even though the diagram and explanation talks about states and transitions,
+ * the callee is only interested in the transistions. The states are mentioned
+ * here for illustrative purposes.
+ *
+ * Startup Scenario: When the device boots up, if an application adds geofences,
+ * and then we get an accurate FLP location fix, it needs to trigger the
+ * appropriate (ENTERED or EXITED) transition for every Geofence it knows about.
+ * By default, all the Geofences will be in the Unknown state.
+ *
+ * When the FLP system is unavailable, flp_geofence_status_callback should be
+ * called to inform the upper layers of the same. Similarly, when it becomes
+ * available the callback should be called. This is a global state while the
+ * UNKNOWN transition described above is per geofence.
+ *
+ */
+#define FLP_GEOFENCE_TRANSITION_ENTERED (1L<<0)
+#define FLP_GEOFENCE_TRANSITION_EXITED (1L<<1)
+#define FLP_GEOFENCE_TRANSITION_UNCERTAIN (1L<<2)
+
+#define FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE (1L<<0)
+#define FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE (1L<<1)
+
+/**
+ * The callback associated with the geofence.
+ * Parameters:
+ * geofence_id - The id associated with the add_geofence_area.
+ * 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; -1 if not available.
+ * sources_used - Bitwise OR of FLP_TECH_MASK flags indicating which
+ * subsystems were used.
+ *
+ * The callback should only be called when the caller is interested in that
+ * particular transition. For instance, if the caller is interested only in
+ * ENTERED transition, then the callback should NOT be called with the EXITED
+ * transition.
+ *
+ * IMPORTANT: If a transition is triggered resulting in this callback, the
+ * subsystem will wake up the application processor, if its in suspend state.
+ */
+typedef void (*flp_geofence_transition_callback) (int32_t geofence_id, FlpLocation* location,
+ int32_t transition, FlpUtcTime timestamp, uint32_t sources_used);
+
+/**
+ * The callback associated with the availablity of one the sources used for geofence
+ * monitoring by the FLP sub-system For example, if the GPS system determines that it cannot
+ * monitor geofences because of lack of reliability or unavailability of the GPS signals,
+ * it will call this callback with FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE parameter and the
+ * source set to FLP_TECH_MASK_GNSS.
+ *
+ * Parameters:
+ * status - FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE or FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE.
+ * source - One of the FLP_TECH_MASKS
+ * last_location - Last known location.
+ */
+typedef void (*flp_geofence_monitor_status_callback) (int32_t status, uint32_t source,
+ FlpLocation* last_location);
+
+/**
+ * The callback associated with the add_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * result - FLP_RESULT_SUCCESS
+ * FLP_RESULT_ERROR_TOO_MANY_GEOFENCES - geofence limit has been reached.
+ * FLP_RESULT_ID_EXISTS - geofence with id already exists
+ * FLP_RESULT_INVALID_GEOFENCE_TRANSITION - the monitorTransition contains an
+ * invalid transition
+ * FLP_RESULT_ERROR - for other errors.
+ */
+typedef void (*flp_geofence_add_callback) (int32_t geofence_id, int32_t result);
+
+/**
+ * The callback associated with the remove_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * result - FLP_RESULT_SUCCESS
+ * FLP_RESULT_ID_UNKNOWN - for invalid id
+ * FLP_RESULT_ERROR for others.
+ */
+typedef void (*flp_geofence_remove_callback) (int32_t geofence_id, int32_t result);
+
+
+/**
+ * The callback associated with the pause_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * result - FLP_RESULT_SUCCESS
+ * FLP_RESULT__ID_UNKNOWN - for invalid id
+ * FLP_RESULT_INVALID_TRANSITION -
+ * when monitor_transitions is invalid
+ * FLP_RESULT_ERROR for others.
+ */
+typedef void (*flp_geofence_pause_callback) (int32_t geofence_id, int32_t result);
+
+/**
+ * The callback associated with the resume_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * result - FLP_RESULT_SUCCESS
+ * FLP_RESULT_ID_UNKNOWN - for invalid id
+ * FLP_RESULT_ERROR for others.
+ */
+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_set_thread_event set_thread_event_cb;
+} FlpGeofenceCallbacks;
+
+
+/** Type of geofence */
+typedef enum {
+ TYPE_CIRCLE = 0,
+} GeofenceType;
+
+/** Circular geofence is represented by lat / long / radius */
+typedef struct {
+ double latitude;
+ double longitude;
+ double radius_m;
+} GeofenceCircle;
+
+/** Represents the type of geofence and data */
+typedef struct {
+ GeofenceType type;
+ union {
+ GeofenceCircle circle;
+ } geofence;
+} GeofenceData;
+
+/** Geofence Options */
+typedef struct {
+ /**
+ * The current state of the geofence. For example, if
+ * the system already knows that the user is inside the geofence,
+ * this will be set to FLP_GEOFENCE_TRANSITION_ENTERED. In most cases, it
+ * will be FLP_GEOFENCE_TRANSITION_UNCERTAIN. */
+ int last_transition;
+
+ /**
+ * Transitions to monitor. Bitwise OR of
+ * FLP_GEOFENCE_TRANSITION_ENTERED, FLP_GEOFENCE_TRANSITION_EXITED and
+ * FLP_GEOFENCE_TRANSITION_UNCERTAIN.
+ */
+ int monitor_transitions;
+
+ /**
+ * Defines the best-effort description
+ * of how soon should the callback be called when the transition
+ * associated with the Geofence is triggered. For instance, if set
+ * to 1000 millseconds with FLP_GEOFENCE_TRANSITION_ENTERED, the callback
+ * should be called 1000 milliseconds within entering the geofence.
+ * This parameter is defined in milliseconds.
+ * NOTE: This is not to be confused with the rate that the GPS is
+ * polled at. It is acceptable to dynamically vary the rate of
+ * sampling the GPS for power-saving reasons; thus the rate of
+ * sampling may be faster or slower than this.
+ */
+ int notification_responsivenes_ms;
+
+ /**
+ * The time limit after which the UNCERTAIN transition
+ * should be triggered. This paramter is defined in milliseconds.
+ */
+ int unknown_timer_ms;
+
+ /**
+ * The sources to use for monitoring geofences. Its a BITWISE-OR
+ * of FLP_TECH_MASK flags.
+ */
+ uint32_t sources_to_use;
+} GeofenceOptions;
+
+/** Geofence struct */
+typedef struct {
+ int32_t geofence_id;
+ GeofenceData* data;
+ GeofenceOptions* options;
+} Geofence;
+
+/** Extended interface for FLP_Geofencing support */
+typedef struct {
+ /** set to sizeof(FlpGeofencingInterface) */
+ size_t size;
+
+ /**
+ * Opens the geofence interface and provides the callback routines
+ * to the implemenation of this interface.
+ */
+ void (*init)( FlpGeofenceCallbacks* callbacks );
+
+ /**
+ * Add a list of geofences.
+ * Parameters:
+ * number_of_geofences - The number of geofences that needed to be added.
+ * geofences - Pointer to array of pointers to Geofence structure.
+ */
+ void (*add_geofences) (int32_t number_of_geofences, Geofence** geofences);
+
+ /**
+ * Pause monitoring a particular geofence.
+ * Parameters:
+ * geofence_id - The id for the geofence.
+ */
+ void (*pause_geofence) (int32_t geofence_id);
+
+ /**
+ * Resume monitoring a particular geofence.
+ * Parameters:
+ * geofence_id - The id for the geofence.
+ * monitor_transitions - Which transitions to monitor. Bitwise OR of
+ * FLP_GEOFENCE_TRANSITION_ENTERED, FLP_GEOFENCE_TRANSITION_EXITED and
+ * FLP_GEOFENCE_TRANSITION_UNCERTAIN.
+ * This supersedes the value associated provided in the
+ * add_geofence_area call.
+ */
+ 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:
+ * number_of_geofences - The number of geofences that needed to be added.
+ * geofence_id - Pointer to array of geofence_ids to be removed.
+ */
+ void (*remove_geofences) (int32_t number_of_geofences, int32_t* geofence_id);
+} FlpGeofencingInterface;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_HARDWARE_FLP_H */
+
diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h
index 9c622421..0dbebcff 100644
--- a/include/hardware/gralloc.h
+++ b/include/hardware/gralloc.h
@@ -104,6 +104,9 @@ enum {
/* 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 d75a0472..846bab49 100644
--- a/include/hardware/hwcomposer.h
+++ b/include/hardware/hwcomposer.h
@@ -54,6 +54,13 @@ typedef struct hwc_rect {
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 @@ typedef struct hwc_layer_1 {
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
@@ -433,12 +449,12 @@ typedef struct hwc_composer_device_1 {
* For HWC 1.0, numDisplays will always be one, and displays[0] will be
* non-NULL.
*
- * For HWC 1.1, numDisplays will always be HWC_NUM_DISPLAY_TYPES. Entries
- * for unsupported or disabled/disconnected display types will be NULL.
+ * For HWC 1.1, numDisplays will always be HWC_NUM_PHYSICAL_DISPLAY_TYPES.
+ * Entries for unsupported or disabled/disconnected display types will be
+ * NULL.
*
- * In a future version, numDisplays may be larger than
- * HWC_NUM_DISPLAY_TYPES. The extra entries correspond to enabled virtual
- * displays, and will be non-NULL.
+ * In HWC 1.3, numDisplays may be up to HWC_NUM_DISPLAY_TYPES. The extra
+ * entries correspond to enabled virtual displays, and will be non-NULL.
*
* returns: 0 on success. An negative error code on error. If an error is
* returned, SurfaceFlinger will assume that none of the layer will be
@@ -466,12 +482,12 @@ typedef struct hwc_composer_device_1 {
* For HWC 1.0, numDisplays will always be one, and displays[0] will be
* non-NULL.
*
- * For HWC 1.1, numDisplays will always be HWC_NUM_DISPLAY_TYPES. Entries
- * for unsupported or disabled/disconnected display types will be NULL.
+ * For HWC 1.1, numDisplays will always be HWC_NUM_PHYSICAL_DISPLAY_TYPES.
+ * Entries for unsupported or disabled/disconnected display types will be
+ * NULL.
*
- * In a future version, numDisplays may be larger than
- * HWC_NUM_DISPLAY_TYPES. The extra entries correspond to enabled virtual
- * displays, and will be non-NULL.
+ * In HWC 1.3, numDisplays may be up to HWC_NUM_DISPLAY_TYPES. The extra
+ * entries correspond to enabled virtual displays, and will be non-NULL.
*
* IMPORTANT NOTE: There is an implicit layer containing opaque black
* pixels behind all the layers in the list. It is the responsibility of
diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h
index 1edfd3da..c69a4bca 100644
--- a/include/hardware/hwcomposer_defs.h
+++ b/include/hardware/hwcomposer_defs.h
@@ -35,6 +35,7 @@ __BEGIN_DECLS
#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 */
@@ -181,12 +182,16 @@ enum {
enum {
HWC_DISPLAY_PRIMARY = 0,
HWC_DISPLAY_EXTERNAL = 1, // HDMI, DP, etc.
- HWC_NUM_DISPLAY_TYPES
+ HWC_DISPLAY_VIRTUAL = 2,
+
+ HWC_NUM_PHYSICAL_DISPLAY_TYPES = 2,
+ HWC_NUM_DISPLAY_TYPES = 3,
};
enum {
HWC_DISPLAY_PRIMARY_BIT = 1 << HWC_DISPLAY_PRIMARY,
HWC_DISPLAY_EXTERNAL_BIT = 1 << HWC_DISPLAY_EXTERNAL,
+ HWC_DISPLAY_VIRTUAL_BIT = 1 << HWC_DISPLAY_VIRTUAL,
};
/*****************************************************************************/
diff --git a/include/hardware/memtrack.h b/include/hardware/memtrack.h
new file mode 100644
index 00000000..57ba4ad7
--- /dev/null
+++ b/include/hardware/memtrack.h
@@ -0,0 +1,160 @@
+/*
+ * 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 ANDROID_INCLUDE_HARDWARE_MEMTRACK_H
+#define ANDROID_INCLUDE_HARDWARE_MEMTRACK_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <hardware/hardware.h>
+
+__BEGIN_DECLS
+
+#define MEMTRACK_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
+
+/**
+ * The id of this module
+ */
+#define MEMTRACK_HARDWARE_MODULE_ID "memtrack"
+
+/*
+ * The Memory Tracker HAL is designed to return information about device-specific
+ * memory usage. The primary goal is to be able to track memory that is not
+ * trackable in any other way, for example texture memory that is allocated by
+ * a process, but not mapped in to that process' address space.
+ * A secondary goal is to be able to categorize memory used by a process into
+ * GL, graphics, etc. All memory sizes should be in real memory usage,
+ * accounting for stride, bit depth, rounding up to page size, etc.
+ *
+ * A process collecting memory statistics will call getMemory for each
+ * combination of pid and memory type. For each memory type that it recognizes
+ * the HAL should fill out an array of memtrack_record structures breaking
+ * down the statistics of that memory type as much as possible. For example,
+ * getMemory(<pid>, MEMTRACK_TYPE_GL) might return:
+ * { { 4096, ACCOUNTED | PRIVATE | SYSTEM },
+ * { 40960, UNACCOUNTED | PRIVATE | SYSTEM },
+ * { 8192, ACCOUNTED | PRIVATE | DEDICATED },
+ * { 8192, UNACCOUNTED | PRIVATE | DEDICATED } }
+ * If the HAL could not differentiate between SYSTEM and DEDICATED memory, it
+ * could return:
+ * { { 12288, ACCOUNTED | PRIVATE },
+ * { 49152, UNACCOUNTED | PRIVATE } }
+ *
+ * Memory should not overlap between types. For example, a graphics buffer
+ * that has been mapped into the GPU as a surface should show up when
+ * MEMTRACK_TYPE_GRAPHICS is requested, and not when MEMTRACK_TYPE_GL
+ * is requested.
+ */
+
+enum memtrack_type {
+ MEMTRACK_TYPE_OTHER = 0,
+ MEMTRACK_TYPE_GL = 1,
+ MEMTRACK_TYPE_GRAPHICS = 2,
+ MEMTRACK_TYPE_MULTIMEDIA = 3,
+ MEMTRACK_TYPE_CAMERA = 4,
+ MEMTRACK_NUM_TYPES,
+};
+
+struct memtrack_record {
+ size_t size_in_bytes;
+ unsigned int flags;
+};
+
+/**
+ * Flags to differentiate memory that can already be accounted for in
+ * /proc/<pid>/smaps,
+ * (Shared_Clean + Shared_Dirty + Private_Clean + Private_Dirty = Size).
+ * In general, memory mapped in to a userspace process is accounted unless
+ * it was mapped with remap_pfn_range.
+ * Exactly one of these should be set.
+ */
+#define MEMTRACK_FLAG_SMAPS_ACCOUNTED (1 << 1)
+#define MEMTRACK_FLAG_SMAPS_UNACCOUNTED (1 << 2)
+
+/**
+ * Flags to differentiate memory shared across multiple processes vs. memory
+ * used by a single process. Only zero or one of these may be set in a record.
+ * If none are set, record is assumed to count shared + private memory.
+ */
+#define MEMTRACK_FLAG_SHARED (1 << 3)
+#define MEMTRACK_FLAG_SHARED_PSS (1 << 4) /* shared / num_procesess */
+#define MEMTRACK_FLAG_PRIVATE (1 << 5)
+
+/**
+ * Flags to differentiate memory taken from the kernel's allocation pool vs.
+ * memory that is dedicated to non-kernel allocations, for example a carveout
+ * or separate video memory. Only zero or one of these may be set in a record.
+ * If none are set, record is assumed to count system + dedicated memory.
+ */
+#define MEMTRACK_FLAG_SYSTEM (1 << 6)
+#define MEMTRACK_FLAG_DEDICATED (1 << 7)
+
+/**
+ * Flags to differentiate memory accessible by the CPU in non-secure mode vs.
+ * memory that is protected. Only zero or one of these may be set in a record.
+ * If none are set, record is assumed to count secure + nonsecure memory.
+ */
+#define MEMTRACK_FLAG_NONSECURE (1 << 8)
+#define MEMTRACK_FLAG_SECURE (1 << 9)
+
+/**
+ * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
+ * and the fields of this data structure must begin with hw_module_t
+ * followed by module specific information.
+ */
+typedef struct memtrack_module {
+ struct hw_module_t common;
+
+ /**
+ * (*init)() performs memtrack management setup actions and is called
+ * once before any calls to getMemory().
+ * Returns 0 on success, -errno on error.
+ */
+ int (*init)(const struct memtrack_module *module);
+
+ /**
+ * (*getMemory)() expects an array of record objects and populates up to
+ * *num_record structures with the sizes of memory plus associated flags for
+ * that memory. It also updates *num_records with the total number of
+ * records it could return if *num_records was large enough when passed in.
+ * Returning records with size 0 is expected, the number of records should
+ * not vary between calls to getMemory for the same memory type, even
+ * for different pids.
+ *
+ * The caller will often call getMemory for a type and pid with
+ * *num_records == 0 to determine how many records to allocate room for,
+ * this case should be a fast-path in the HAL, returning a constant and
+ * not querying any kernel files. If *num_records passed in is 0,
+ * then records may be NULL.
+ *
+ * This function must be thread-safe, it may get called from multiple
+ * threads at the same time.
+ *
+ * Returns 0 on success, -ENODEV if the type is not supported, -errno
+ * on other errors.
+ */
+ int (*getMemory)(const struct memtrack_module *module,
+ pid_t pid,
+ int type,
+ struct memtrack_record *records,
+ size_t *num_records);
+} memtrack_module_t;
+
+__END_DECLS
+
+#endif // ANDROID_INCLUDE_HARDWARE_MEMTRACK_H
diff --git a/include/hardware/sensors.h b/include/hardware/sensors.h
index 7778e8f1..4c13848b 100644
--- a/include/hardware/sensors.h
+++ b/include/hardware/sensors.h
@@ -32,6 +32,7 @@ __BEGIN_DECLS
#define SENSORS_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
#define SENSORS_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION_2(0, 1, SENSORS_HEADER_VERSION)
#define SENSORS_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION_2(1, 0, SENSORS_HEADER_VERSION)
+#define SENSORS_DEVICE_API_VERSION_1_1 HARDWARE_DEVICE_API_VERSION_2(1, 1, SENSORS_HEADER_VERSION)
/**
* The id of this module
@@ -64,6 +65,15 @@ enum {
SENSORS_BATCH_WAKE_UPON_FIFO_FULL = 0x00000002
};
+/*
+ * what field for meta_data_event_t
+ */
+enum {
+ /* a previous flush operation has completed */
+ META_DATA_FLUSH_COMPLETE = 1,
+ META_DATA_VERSION /* always last, leave auto-assigned */
+};
+
/**
* Definition of the axis used by the sensor HAL API
*
@@ -132,9 +142,20 @@ enum {
*
* Each sensor has a type which defines what this sensor measures and how
* measures are reported. All types are defined below.
+ *
+ * Device manufacturers (OEMs) can define their own sensor types, for
+ * their private use by applications or services provided by them. Such
+ * sensor types are specific to an OEM and can't be exposed in the SDK.
+ * These types must start at SENSOR_TYPE_DEVICE_PRIVATE_BASE.
*/
/*
+ * Base for device manufacturers private sensor types.
+ * These sensor types can't be exposed in the SDK.
+ */
+#define SENSOR_TYPE_DEVICE_PRIVATE_BASE 0x10000
+
+/*
* Sensor fusion and virtual sensors
*
* Many sensor types are or can be implemented as virtual sensors from
@@ -174,6 +195,40 @@ enum {
*
*/
+
+/*
+ * SENSOR_TYPE_META_DATA
+ * trigger-mode: n/a
+ * wake-up sensor: n/a
+ *
+ * NO SENSOR OF THAT TYPE MUST BE RETURNED (*get_sensors_list)()
+ *
+ * SENSOR_TYPE_META_DATA is a special token used to populate the
+ * sensors_meta_data_event structure. It doesn't correspond to a physical
+ * sensor. sensors_meta_data_event are special, they exist only inside
+ * the HAL and are generated spontaneously, as opposed to be related to
+ * a physical sensor.
+ *
+ * sensors_meta_data_event_t.version must be META_DATA_VERSION
+ * sensors_meta_data_event_t.sensor must be 0
+ * sensors_meta_data_event_t.type must be SENSOR_TYPE_META_DATA
+ * sensors_meta_data_event_t.reserved must be 0
+ * sensors_meta_data_event_t.timestamp must be 0
+ *
+ * The payload is a meta_data_event_t, where:
+ * meta_data_event_t.what can take the following values:
+ *
+ * META_DATA_FLUSH_COMPLETE
+ * This event indicates that a previous (*flush)() call has completed for the sensor
+ * handle specified in meta_data_event_t.sensor.
+ * see (*flush)() for more details
+ *
+ * All other values for meta_data_event_t.what are reserved and
+ * must not be used.
+ *
+ */
+#define SENSOR_TYPE_META_DATA (0)
+
/*
* SENSOR_TYPE_ACCELEROMETER
* trigger-mode: continuous
@@ -451,6 +506,9 @@ enum {
* 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 +666,7 @@ enum {
*
* 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 +720,9 @@ enum {
* 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:
@@ -740,6 +800,11 @@ typedef struct {
};
} uncalibrated_event_t;
+typedef struct meta_data_event {
+ int32_t what;
+ int32_t sensor;
+} meta_data_event_t;
+
/**
* Union of the various types of sensor data
* that can be returned.
@@ -761,48 +826,63 @@ typedef struct sensors_event_t {
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;
+ /* this is a special event. see SENSOR_TYPE_META_DATA above.
+ * sensors_meta_data_event_t events are all reported with a type of
+ * SENSOR_TYPE_META_DATA. The handle is ignored and must be zero.
+ */
+ meta_data_event_t meta_data;
+ };
+
+ union {
+ uint64_t data[8];
+
+ /* step-counter */
+ uint64_t step_counter;
+ } u64;
};
- uint32_t reserved1[4];
+ uint32_t reserved1[4];
} sensors_event_t;
+/* see SENSOR_TYPE_META_DATA */
+typedef sensors_event_t sensors_meta_data_event_t;
+
struct sensor_t;
@@ -865,8 +945,21 @@ struct sensor_t {
*/
int32_t minDelay;
+ /* number of events reserved for this sensor in the batch mode FIFO.
+ * If there is a dedicated FIFO for this sensor, then this is the
+ * size of this FIFO. If the FIFO is shared with other sensors,
+ * this is the size reserved for that sensor and it can be zero.
+ */
+ uint32_t fifoReservedEventCount;
+
+ /* maximum number of events of this sensor that could be batched.
+ * This is especially relevant when the FIFO is shared between
+ * several sensors; this value is then set to the size of that FIFO.
+ */
+ uint32_t fifoMaxEventCount;
+
/* reserved fields, must be zero */
- void* reserved[8];
+ void* reserved[6];
};
@@ -903,6 +996,10 @@ typedef struct sensors_poll_device_1 {
* 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 +1009,10 @@ typedef struct sensors_poll_device_1 {
* 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 +1036,9 @@ typedef struct sensors_poll_device_1 {
* 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 +1168,30 @@ typedef struct sensors_poll_device_1 {
* 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:
@@ -1150,6 +1261,35 @@ typedef struct sensors_poll_device_1 {
int (*batch)(struct sensors_poll_device_1* dev,
int handle, int flags, int64_t period_ns, int64_t timeout);
+ /*
+ * Flush adds a META_DATA_FLUSH_COMPLETE event (sensors_event_meta_data_t)
+ * to the end of the "batch mode" FIFO for the specified sensor and flushes
+ * the FIFO; those events are delivered as usual (i.e.: as if the batch
+ * timeout had expired) and removed from the FIFO.
+ *
+ * See the META_DATA_FLUSH_COMPLETE section for details about the
+ * META_DATA_FLUSH_COMPLETE event.
+ *
+ * The flush happens asynchronously (i.e.: this function must return
+ * immediately).
+ *
+ * If the implementation uses a single FIFO for several sensors, that
+ * FIFO is flushed and the META_DATA_FLUSH_COMPLETE event is added only
+ * for the specified sensor.
+ *
+ * If the specified sensor wasn't in batch mode, flush succeeds and
+ * promptly sends a META_DATA_FLUSH_COMPLETE event for that sensor.
+ *
+ * If the FIFO was empty at the time of the call, flush returns
+ * 0 (success) and promptly sends a META_DATA_FLUSH_COMPLETE event
+ * for that sensor.
+ *
+ * If the specified sensor wasn't enabled, flush returns -EINVAL.
+ *
+ * return 0 on success, negative errno code otherwise.
+ */
+ int (*flush)(struct sensors_poll_device_1* dev, int handle);
+
void (*reserved_procs[8])(void);
} sensors_poll_device_1_t;
diff --git a/modules/Android.mk b/modules/Android.mk
index 486b42dd..b2d5a2a7 100644
--- a/modules/Android.mk
+++ b/modules/Android.mk
@@ -1,2 +1,3 @@
-hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time power usbaudio audio_remote_submix camera
+hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time \
+ power usbaudio audio_remote_submix camera consumerir
include $(call all-named-subdir-makefiles,$(hardware_modules))
diff --git a/modules/audio/audio_policy.c b/modules/audio/audio_policy.c
index 2dd3dbef..9335654e 100644
--- a/modules/audio/audio_policy.c
+++ b/modules/audio/audio_policy.c
@@ -99,7 +99,8 @@ static audio_io_handle_t ap_get_output(struct audio_policy *pol,
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 @@ static int ap_dump(const struct audio_policy *pol, int fd)
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 @@ static int create_default_ap(const struct audio_policy_device *device,
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/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp
index 5e88ef73..9df17b64 100755..100644
--- a/modules/audio_remote_submix/audio_hw.cpp
+++ b/modules/audio_remote_submix/audio_hw.cpp
@@ -271,7 +271,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
return 0;
} else {
// write() returned UNDERRUN or WOULD_BLOCK, retry
- ALOGE("out_write() write to pipe returned unexpected %16lx", written_frames);
+ ALOGE("out_write() write to pipe returned unexpected %d", written_frames);
written_frames = sink->write(buffer, frames);
}
}
@@ -281,7 +281,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
pthread_mutex_unlock(&out->dev->lock);
if (written_frames < 0) {
- ALOGE("out_write() failed writing to pipe with %16lx", written_frames);
+ ALOGE("out_write() failed writing to pipe with %d", written_frames);
return 0;
} else {
ALOGV("out_write() wrote %lu bytes)", written_frames * frame_size);
@@ -549,7 +549,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
rsxadev->config.channel_mask = config->channel_mask;
- if ((config->sample_rate != 48000) || (config->sample_rate != 44100)) {
+ if ((config->sample_rate != 48000) && (config->sample_rate != 44100)) {
config->sample_rate = DEFAULT_RATE_HZ;
}
rsxadev->config.rate = config->sample_rate;
@@ -708,7 +708,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
rsxadev->config.channel_mask = config->channel_mask;
- if ((config->sample_rate != 48000) || (config->sample_rate != 44100)) {
+ if ((config->sample_rate != 48000) && (config->sample_rate != 44100)) {
config->sample_rate = DEFAULT_RATE_HZ;
}
rsxadev->config.rate = config->sample_rate;
diff --git a/modules/camera/Android.mk b/modules/camera/Android.mk
index eebffc12..e02a143d 100644
--- a/modules/camera/Android.mk
+++ b/modules/camera/Android.mk
@@ -26,11 +26,14 @@ LOCAL_C_INCLUDES += \
LOCAL_SRC_FILES := \
CameraHAL.cpp \
Camera.cpp \
+ Metadata.cpp \
+ Stream.cpp \
LOCAL_SHARED_LIBRARIES := \
libcamera_metadata \
libcutils \
liblog \
+ libsync \
LOCAL_CFLAGS += -Wall -Wextra -fvisibility=hidden
diff --git a/modules/camera/Camera.cpp b/modules/camera/Camera.cpp
index 203b7727..973380ef 100644
--- a/modules/camera/Camera.cpp
+++ b/modules/camera/Camera.cpp
@@ -17,7 +17,12 @@
#include <cstdlib>
#include <pthread.h>
#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
#define LOG_TAG "Camera"
@@ -25,9 +30,14 @@
#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
#include <cutils/trace.h>
+#include "ScopedTrace.h"
#include "Camera.h"
+#define CAMERA_SYNC_TIMEOUT 5000 // in msecs
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
namespace default_camera_hal {
extern "C" {
@@ -42,14 +52,19 @@ static int close_device(hw_device_t* dev)
Camera::Camera(int id)
: mId(id),
+ mStaticInfo(NULL),
mBusy(false),
- mCallbackOps(NULL)
+ mCallbackOps(NULL),
+ mStreams(NULL),
+ mNumStreams(0),
+ mSettings(NULL)
{
- pthread_mutex_init(&mMutex,
- NULL); // No pthread mutex attributes.
+ pthread_mutex_init(&mMutex, NULL);
+ pthread_mutex_init(&mStaticInfoMutex, NULL);
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;
@@ -57,16 +72,17 @@ Camera::Camera(int id)
Camera::~Camera()
{
+ pthread_mutex_destroy(&mMutex);
+ pthread_mutex_destroy(&mStaticInfoMutex);
}
int Camera::open(const hw_module_t *module, hw_device_t **device)
{
ALOGI("%s:%d: Opening camera device", __func__, mId);
- ATRACE_BEGIN(__func__);
+ CAMTRACE_CALL();
pthread_mutex_lock(&mMutex);
if (mBusy) {
pthread_mutex_unlock(&mMutex);
- ATRACE_END();
ALOGE("%s:%d: Error! Camera device already opened", __func__, mId);
return -EBUSY;
}
@@ -77,18 +93,33 @@ int Camera::open(const hw_module_t *module, hw_device_t **device)
*device = &mDevice.common;
pthread_mutex_unlock(&mMutex);
- ATRACE_END();
+ return 0;
+}
+
+int Camera::getInfo(struct camera_info *info)
+{
+ info->facing = CAMERA_FACING_FRONT;
+ info->orientation = 0;
+ info->device_version = mDevice.common.version;
+
+ pthread_mutex_lock(&mStaticInfoMutex);
+ if (mStaticInfo == NULL) {
+ mStaticInfo = initStaticInfo();
+ }
+ pthread_mutex_unlock(&mStaticInfoMutex);
+
+ info->static_camera_characteristics = mStaticInfo;
+
return 0;
}
int Camera::close()
{
ALOGI("%s:%d: Closing camera device", __func__, mId);
- ATRACE_BEGIN(__func__);
+ CAMTRACE_CALL();
pthread_mutex_lock(&mMutex);
if (!mBusy) {
pthread_mutex_unlock(&mMutex);
- ATRACE_END();
ALOGE("%s:%d: Error! Camera device not open", __func__, mId);
return -EINVAL;
}
@@ -97,7 +128,6 @@ int Camera::close()
mBusy = false;
pthread_mutex_unlock(&mMutex);
- ATRACE_END();
return 0;
}
@@ -105,44 +135,500 @@ int Camera::initialize(const camera3_callback_ops_t *callback_ops)
{
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::configureStreams(camera3_stream_configuration_t *stream_list)
+camera_metadata_t *Camera::initStaticInfo()
+{
+ /*
+ * Setup static camera info. This will have to customized per camera
+ * device.
+ */
+ Metadata m;
+
+ /* android.control */
+ int32_t android_control_ae_available_target_fps_ranges[] = {30, 30};
+ m.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};
+ m.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}};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.addInt32(ANDROID_SCALER_AVAILABLE_FORMATS,
+ ARRAY_SIZE(android_scaler_available_formats),
+ android_scaler_available_formats);
+
+ int64_t android_scaler_available_jpeg_min_durations[] = {1};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.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};
+ m.addInt32(ANDROID_SENSOR_ORIENTATION,
+ ARRAY_SIZE(android_sensor_orientation),
+ android_sensor_orientation);
+
+ /* End of static camera characteristics */
+
+ return clone_camera_metadata(m.generate());
+}
+
+int Camera::configureStreams(camera3_stream_configuration_t *stream_config)
{
- ALOGV("%s:%d: stream_list=%p", __func__, mId, stream_list);
- // TODO: validate input, create internal stream representations
+ camera3_stream_t *astream;
+ Stream **newStreams = NULL;
+
+ CAMTRACE_CALL();
+ ALOGV("%s:%d: stream_config=%p", __func__, mId, stream_config);
+
+ if (stream_config == NULL) {
+ ALOGE("%s:%d: NULL stream configuration array", __func__, mId);
+ return -EINVAL;
+ }
+ if (stream_config->num_streams == 0) {
+ ALOGE("%s:%d: Empty stream configuration array", __func__, mId);
+ return -EINVAL;
+ }
+
+ // Create new stream array
+ newStreams = new Stream*[stream_config->num_streams];
+ ALOGV("%s:%d: Number of Streams: %d", __func__, mId,
+ stream_config->num_streams);
+
+ pthread_mutex_lock(&mMutex);
+
+ // Mark all current streams unused for now
+ for (int i = 0; i < mNumStreams; i++)
+ mStreams[i]->mReuse = false;
+ // Fill new stream array with reused streams and new streams
+ for (unsigned int i = 0; i < stream_config->num_streams; i++) {
+ astream = stream_config->streams[i];
+ if (astream->max_buffers > 0) {
+ ALOGV("%s:%d: Reusing stream %d", __func__, mId, i);
+ newStreams[i] = reuseStream(astream);
+ } 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);
+ goto err_out;
+ }
+ astream->priv = newStreams[i];
+ }
+
+ // Verify the set of streams in aggregate
+ if (!isValidStreamSet(newStreams, stream_config->num_streams)) {
+ ALOGE("%s:%d: Invalid stream set", __func__, mId);
+ goto err_out;
+ }
+
+ // Set up all streams (calculate usage/max_buffers for each)
+ setupStreams(newStreams, stream_config->num_streams);
+
+ // Destroy all old streams and replace stream array with new one
+ destroyStreams(mStreams, mNumStreams);
+ mStreams = newStreams;
+ mNumStreams = stream_config->num_streams;
+
+ // Clear out last seen settings metadata
+ setSettings(NULL);
+
+ pthread_mutex_unlock(&mMutex);
return 0;
+
+err_out:
+ // Clean up temporary streams, preserve existing mStreams/mNumStreams
+ destroyStreams(newStreams, stream_config->num_streams);
+ pthread_mutex_unlock(&mMutex);
+ return -EINVAL;
+}
+
+void Camera::destroyStreams(Stream **streams, int count)
+{
+ if (streams == NULL)
+ return;
+ for (int i = 0; i < count; i++) {
+ // Only destroy streams that weren't reused
+ if (streams[i] != NULL && !streams[i]->mReuse)
+ delete streams[i];
+ }
+ delete [] streams;
+}
+
+Stream *Camera::reuseStream(camera3_stream_t *astream)
+{
+ Stream *priv = reinterpret_cast<Stream*>(astream->priv);
+ // Verify the re-used stream's parameters match
+ if (!priv->isValidReuseStream(mId, astream)) {
+ ALOGE("%s:%d: Mismatched parameter in reused stream", __func__, mId);
+ return NULL;
+ }
+ // Mark stream to be reused
+ priv->mReuse = true;
+ return priv;
+}
+
+bool Camera::isValidStreamSet(Stream **streams, int count)
+{
+ int inputs = 0;
+ int outputs = 0;
+
+ if (streams == NULL) {
+ ALOGE("%s:%d: NULL stream configuration streams", __func__, mId);
+ return false;
+ }
+ if (count == 0) {
+ ALOGE("%s:%d: Zero count stream configuration streams", __func__, mId);
+ return false;
+ }
+ // Validate there is at most one input stream and at least one output stream
+ for (int i = 0; i < count; i++) {
+ // A stream may be both input and output (bidirectional)
+ if (streams[i]->isInputType())
+ inputs++;
+ 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;
+ }
+ if (inputs > 1) {
+ ALOGE("%s:%d: Stream config must have <= 1 input", __func__, mId);
+ return false;
+ }
+ // TODO: check for correct number of Bayer/YUV/JPEG/Encoder streams
+ return true;
+}
+
+void Camera::setupStreams(Stream **streams, int count)
+{
+ /*
+ * This is where the HAL has to decide internally how to handle all of the
+ * streams, and then produce usage and max_buffer values for each stream.
+ * Note, the stream array has been checked before this point for ALL invalid
+ * conditions, so it must find a successful configuration for this stream
+ * array. The HAL may not return an error from this point.
+ *
+ * In this demo HAL, we just set all streams to be the same dummy values;
+ * real implementations will want to avoid USAGE_SW_{READ|WRITE}_OFTEN.
+ */
+ for (int i = 0; i < count; i++) {
+ uint32_t usage = 0;
+
+ if (streams[i]->isOutputType())
+ usage |= GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_CAMERA_WRITE;
+ if (streams[i]->isInputType())
+ usage |= GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_HW_CAMERA_READ;
+
+ streams[i]->setUsage(usage);
+ streams[i]->setMaxBuffers(1);
+ }
}
int Camera::registerStreamBuffers(const camera3_stream_buffer_set_t *buf_set)
{
ALOGV("%s:%d: buffer_set=%p", __func__, mId, buf_set);
- // TODO: register buffers with hardware
- return 0;
+ if (buf_set == NULL) {
+ ALOGE("%s:%d: NULL buffer set", __func__, mId);
+ return -EINVAL;
+ }
+ if (buf_set->stream == NULL) {
+ ALOGE("%s:%d: NULL stream handle", __func__, mId);
+ return -EINVAL;
+ }
+ Stream *stream = reinterpret_cast<Stream*>(buf_set->stream->priv);
+ return stream->registerBuffers(buf_set);
}
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)
{
+ camera3_capture_result result;
+
ALOGV("%s:%d: request=%p", __func__, mId, request);
- ATRACE_BEGIN(__func__);
+ CAMTRACE_CALL();
if (request == NULL) {
ALOGE("%s:%d: NULL request recieved", __func__, mId);
- ATRACE_END();
return -EINVAL;
}
- // TODO: verify request; submit request to hardware
- ATRACE_END();
+ ALOGV("%s:%d: Request Frame:%d Settings:%p", __func__, mId,
+ request->frame_number, request->settings);
+
+ // NULL indicates use last settings
+ if (request->settings == NULL) {
+ if (mSettings == NULL) {
+ ALOGE("%s:%d: NULL settings without previous set Frame:%d Req:%p",
+ __func__, mId, request->frame_number, request);
+ return -EINVAL;
+ }
+ } else {
+ setSettings(request->settings);
+ }
+
+ if (request->input_buffer != NULL) {
+ ALOGV("%s:%d: Reprocessing input buffer %p", __func__, mId,
+ request->input_buffer);
+
+ if (!isValidReprocessSettings(request->settings)) {
+ ALOGE("%s:%d: Invalid settings for reprocess request: %p",
+ __func__, mId, request->settings);
+ return -EINVAL;
+ }
+ } else {
+ ALOGV("%s:%d: Capturing new frame.", __func__, mId);
+
+ if (!isValidCaptureSettings(request->settings)) {
+ ALOGE("%s:%d: Invalid settings for capture request: %p",
+ __func__, mId, request->settings);
+ return -EINVAL;
+ }
+ }
+
+ if (request->num_output_buffers <= 0) {
+ ALOGE("%s:%d: Invalid number of output buffers: %d", __func__, mId,
+ request->num_output_buffers);
+ return -EINVAL;
+ }
+ result.num_output_buffers = request->num_output_buffers;
+ result.output_buffers = new camera3_stream_buffer_t[result.num_output_buffers];
+ for (unsigned int i = 0; i < request->num_output_buffers; i++) {
+ int res = processCaptureBuffer(&request->output_buffers[i],
+ const_cast<camera3_stream_buffer_t*>(&result.output_buffers[i]));
+ if (res)
+ goto err_out;
+ }
+
+ result.frame_number = request->frame_number;
+ // 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;
+
+err_out:
+ delete [] result.output_buffers;
+ // TODO: this should probably be a total device failure; transient for now
+ return -EINVAL;
+}
+
+void Camera::setSettings(const camera_metadata_t *new_settings)
+{
+ if (mSettings != NULL) {
+ free_camera_metadata(mSettings);
+ mSettings = NULL;
+ }
+
+ if (new_settings != NULL)
+ mSettings = clone_camera_metadata(new_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*/)
+{
+ // TODO: reject settings that cannot be reprocessed
+ // input buffers unimplemented, use this to reject reprocessing requests
+ ALOGE("%s:%d: Input buffer reprocessing not implemented", __func__, mId);
+ return false;
+}
+
+int Camera::processCaptureBuffer(const camera3_stream_buffer_t *in,
+ camera3_stream_buffer_t *out)
+{
+ 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;
+ out->buffer = in->buffer;
+ out->status = CAMERA3_BUFFER_STATUS_OK;
+ // TODO: use driver-backed release fences
+ out->acquire_fence = -1;
+ out->release_fence = -1;
+
+ // TODO: lock and software-paint buffer
+ 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)
@@ -153,7 +639,7 @@ void Camera::getMetadataVendorTagOps(vendor_tag_query_ops_t *ops)
void Camera::dump(int fd)
{
- ALOGV("%s:%d: Dumping to fd %d", fd);
+ ALOGV("%s:%d: Dumping to fd %d", __func__, mId, fd);
// TODO: dprintf all relevant state to fd
}
diff --git a/modules/camera/Camera.h b/modules/camera/Camera.h
index f2ad0934..be672f90 100644
--- a/modules/camera/Camera.h
+++ b/modules/camera/Camera.h
@@ -20,6 +20,8 @@
#include <pthread.h>
#include <hardware/hardware.h>
#include <hardware/camera3.h>
+#include "Metadata.h"
+#include "Stream.h"
namespace default_camera_hal {
// Camera represents a physical camera on a device.
@@ -35,6 +37,7 @@ class Camera {
// 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>)
@@ -50,8 +53,34 @@ class Camera {
camera3_device_t mDevice;
private:
+ // Separate initialization method for static metadata
+ camera_metadata_t *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
+ void destroyStreams(Stream **array, int count);
+ // Verify a set of streams is valid in aggregate
+ bool isValidStreamSet(Stream **array, int count);
+ // Calculate usage and max_bufs of each stream
+ void setupStreams(Stream **array, int count);
+ // Copy new settings for re-use and clean up old settings.
+ void setSettings(const camera_metadata_t *new_settings);
+ // Verify settings are valid for a capture
+ bool isValidCaptureSettings(const camera_metadata_t *settings);
+ // Verify settings are valid for reprocessing an input buffer
+ bool isValidReprocessSettings(const camera_metadata_t *settings);
+ // 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
@@ -60,6 +89,17 @@ class Camera {
const camera3_callback_ops_t *mCallbackOps;
// Lock protecting the Camera object for modifications
pthread_mutex_t mMutex;
+ // Lock protecting only static camera characteristics, which may
+ // be accessed without the camera device open
+ pthread_mutex_t mStaticInfoMutex;
+ // Array of handles to streams currently in use by the device
+ 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;
};
} // namespace default_camera_hal
diff --git a/modules/camera/CameraHAL.cpp b/modules/camera/CameraHAL.cpp
index 6cae7d22..dfbbe4ca 100644
--- a/modules/camera/CameraHAL.cpp
+++ b/modules/camera/CameraHAL.cpp
@@ -76,7 +76,7 @@ int CameraHAL::getCameraInfo(int id, struct camera_info* info)
return -ENODEV;
}
// TODO: return device-specific static metadata
- return 0;
+ return mCameras[id]->getInfo(info);
}
int CameraHAL::setCallbacks(const camera_module_callbacks_t *callbacks)
@@ -90,11 +90,14 @@ int CameraHAL::open(const hw_module_t* mod, const char* name, hw_device_t** dev)
{
int id;
char *nameEnd;
- Camera *cam;
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 00000000..d5854f9a
--- /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 00000000..22d2f223
--- /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/ScopedTrace.h b/modules/camera/ScopedTrace.h
new file mode 100644
index 00000000..ed005709
--- /dev/null
+++ b/modules/camera/ScopedTrace.h
@@ -0,0 +1,51 @@
+/*
+ * 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 CAMERA_SCOPED_TRACE_H
+#define CAMERA_SCOPED_TRACE_H
+
+#include <stdint.h>
+#include <cutils/trace.h>
+
+// See <cutils/trace.h> for more tracing macros.
+
+// CAMTRACE_NAME traces the beginning and end of the current scope. To trace
+// the correct start and end times this macro should be declared first in the
+// scope body.
+#define CAMTRACE_NAME(name) ScopedTrace ___tracer(ATRACE_TAG, name)
+// CAMTRACE_CALL is an ATRACE_NAME that uses the current function name.
+#define CAMTRACE_CALL() CAMTRACE_NAME(__FUNCTION__)
+
+namespace default_camera_hal {
+
+class ScopedTrace {
+public:
+inline ScopedTrace(uint64_t tag, const char* name)
+ : mTag(tag) {
+ atrace_begin(mTag,name);
+}
+
+inline ~ScopedTrace() {
+ atrace_end(mTag);
+}
+
+private:
+ uint64_t mTag;
+};
+
+}; // namespace default_camera_hal
+
+#endif // CAMERA_SCOPED_TRACE_H
diff --git a/modules/camera/Stream.cpp b/modules/camera/Stream.cpp
new file mode 100644
index 00000000..aae7adb8
--- /dev/null
+++ b/modules/camera/Stream.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Stream"
+#include <cutils/log.h>
+
+#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
+#include <cutils/trace.h>
+#include "ScopedTrace.h"
+
+#include "Stream.h"
+
+namespace default_camera_hal {
+
+Stream::Stream(int id, camera3_stream_t *s)
+ : mReuse(false),
+ mId(id),
+ mStream(s),
+ mType(s->stream_type),
+ mWidth(s->width),
+ mHeight(s->height),
+ mFormat(s->format),
+ mUsage(0),
+ mMaxBuffers(0),
+ mRegistered(false),
+ mBuffers(0),
+ mNumBuffers(0)
+{
+ // NULL (default) pthread mutex attributes
+ pthread_mutex_init(&mMutex, NULL);
+}
+
+Stream::~Stream()
+{
+ pthread_mutex_lock(&mMutex);
+ unregisterBuffers_L();
+ pthread_mutex_unlock(&mMutex);
+}
+
+void Stream::setUsage(uint32_t usage)
+{
+ pthread_mutex_lock(&mMutex);
+ if (usage != mUsage) {
+ mUsage = usage;
+ mStream->usage = usage;
+ unregisterBuffers_L();
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+void Stream::setMaxBuffers(uint32_t max_buffers)
+{
+ pthread_mutex_lock(&mMutex);
+ if (max_buffers != mMaxBuffers) {
+ mMaxBuffers = max_buffers;
+ mStream->max_buffers = max_buffers;
+ unregisterBuffers_L();
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+int Stream::getType()
+{
+ return mType;
+}
+
+bool Stream::isInputType()
+{
+ return mType == CAMERA3_STREAM_INPUT ||
+ mType == CAMERA3_STREAM_BIDIRECTIONAL;
+}
+
+bool Stream::isOutputType()
+{
+ return mType == CAMERA3_STREAM_OUTPUT ||
+ mType == CAMERA3_STREAM_BIDIRECTIONAL;
+}
+
+bool Stream::isRegistered()
+{
+ return mRegistered;
+}
+
+bool Stream::isValidReuseStream(int id, camera3_stream_t *s)
+{
+ if (id != mId) {
+ ALOGE("%s:%d: Invalid camera id for reuse. Got %d expect %d",
+ __func__, mId, id, mId);
+ return false;
+ }
+ if (s != mStream) {
+ ALOGE("%s:%d: Invalid stream handle for reuse. Got %p expect %p",
+ __func__, mId, s, mStream);
+ return false;
+ }
+ if (s->stream_type != mType) {
+ // TODO: prettyprint type string
+ ALOGE("%s:%d: Mismatched type in reused stream. Got %d expect %d",
+ __func__, mId, s->stream_type, mType);
+ return false;
+ }
+ if (s->format != mFormat) {
+ // TODO: prettyprint format string
+ ALOGE("%s:%d: Mismatched format in reused stream. Got %d expect %d",
+ __func__, mId, s->format, mFormat);
+ return false;
+ }
+ if (s->width != mWidth) {
+ ALOGE("%s:%d: Mismatched width in reused stream. Got %d expect %d",
+ __func__, mId, s->width, mWidth);
+ return false;
+ }
+ if (s->height != mHeight) {
+ ALOGE("%s:%d: Mismatched height in reused stream. Got %d expect %d",
+ __func__, mId, s->height, mHeight);
+ return false;
+ }
+ return true;
+}
+
+int Stream::registerBuffers(const camera3_stream_buffer_set_t *buf_set)
+{
+ CAMTRACE_CALL();
+
+ if (buf_set->stream != mStream) {
+ ALOGE("%s:%d: Buffer set for invalid stream. Got %p expect %p",
+ __func__, mId, buf_set->stream, mStream);
+ return -EINVAL;
+ }
+
+ pthread_mutex_lock(&mMutex);
+
+ mNumBuffers = buf_set->num_buffers;
+ mBuffers = new buffer_handle_t*[mNumBuffers];
+
+ for (unsigned int i = 0; i < mNumBuffers; i++) {
+ ALOGV("%s:%d: Registering buffer %p", __func__, mId,
+ buf_set->buffers[i]);
+ mBuffers[i] = buf_set->buffers[i];
+ // TODO: register buffers with hw, handle error cases
+ }
+ mRegistered = true;
+
+ pthread_mutex_unlock(&mMutex);
+
+ return 0;
+}
+
+// This must only be called with mMutex held
+void Stream::unregisterBuffers_L()
+{
+ mRegistered = false;
+ mNumBuffers = 0;
+ delete [] mBuffers;
+ // TODO: unregister buffers from hw
+}
+
+} // namespace default_camera_hal
diff --git a/modules/camera/Stream.h b/modules/camera/Stream.h
new file mode 100644
index 00000000..34abd958
--- /dev/null
+++ b/modules/camera/Stream.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 STREAM_H_
+#define STREAM_H_
+
+#include <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+namespace default_camera_hal {
+// Stream represents a single input or output stream for a camera device.
+class Stream {
+ public:
+ Stream(int id, camera3_stream_t *s);
+ ~Stream();
+
+ // validate that astream's parameters match this stream's parameters
+ bool isValidReuseStream(int id, camera3_stream_t *s);
+
+ // Register buffers with hardware
+ int registerBuffers(const camera3_stream_buffer_set_t *buf_set);
+
+ void setUsage(uint32_t usage);
+ void setMaxBuffers(uint32_t max_buffers);
+
+ int getType();
+ bool isInputType();
+ bool isOutputType();
+ bool isRegistered();
+
+ // This stream is being reused. Used in stream configuration passes
+ bool mReuse;
+
+ private:
+ // Clean up buffer state. must be called with mMutex held.
+ void unregisterBuffers_L();
+
+ // The camera device id this stream belongs to
+ const int mId;
+ // Handle to framework's stream, used as a cookie for buffers
+ camera3_stream_t *mStream;
+ // Stream type: CAMERA3_STREAM_* (see <hardware/camera3.h>)
+ const int mType;
+ // Width in pixels of the buffers in this stream
+ const uint32_t mWidth;
+ // Height in pixels of the buffers in this stream
+ const uint32_t mHeight;
+ // Gralloc format: HAL_PIXEL_FORMAT_* (see <system/graphics.h>)
+ const int mFormat;
+ // Gralloc usage mask : GRALLOC_USAGE_* (see <hardware/gralloc.h>)
+ uint32_t mUsage;
+ // Max simultaneous in-flight buffers for this stream
+ uint32_t mMaxBuffers;
+ // Buffers have been registered for this stream and are ready
+ bool mRegistered;
+ // Array of handles to buffers currently in use by the stream
+ buffer_handle_t **mBuffers;
+ // Number of buffers in mBuffers
+ unsigned int mNumBuffers;
+ // Lock protecting the Stream object for modifications
+ pthread_mutex_t mMutex;
+};
+} // namespace default_camera_hal
+
+#endif // STREAM_H_
diff --git a/modules/consumerir/Android.mk b/modules/consumerir/Android.mk
new file mode 100644
index 00000000..ed6aa0f1
--- /dev/null
+++ b/modules/consumerir/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := consumerir.default
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_SRC_FILES := consumerir.c
+LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/modules/consumerir/consumerir.c b/modules/consumerir/consumerir.c
new file mode 100644
index 00000000..83eba757
--- /dev/null
+++ b/modules/consumerir/consumerir.c
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "ConsumerIrHal"
+
+#include <errno.h>
+#include <string.h>
+#include <cutils/log.h>
+#include <hardware/hardware.h>
+#include <hardware/consumerir.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static const consumerir_freq_range_t consumerir_freqs[] = {
+ {.min = 30000, .max = 30000},
+ {.min = 33000, .max = 33000},
+ {.min = 36000, .max = 36000},
+ {.min = 38000, .max = 38000},
+ {.min = 40000, .max = 40000},
+ {.min = 56000, .max = 56000},
+};
+
+static int consumerir_transmit(struct consumerir_device *dev,
+ int carrier_freq, int pattern[], int pattern_len)
+{
+ int total_time = 0;
+ long i;
+
+ for (i = 0; i < pattern_len; i++)
+ total_time += pattern[i];
+
+ /* simulate the time spent transmitting by sleeping */
+ ALOGD("transmit for %d uS at %d Hz", total_time, carrier_freq);
+ usleep(total_time);
+
+ return 0;
+}
+
+static int consumerir_get_num_carrier_freqs(struct consumerir_device *dev)
+{
+ return ARRAY_SIZE(consumerir_freqs);
+}
+
+static int consumerir_get_carrier_freqs(struct consumerir_device *dev,
+ size_t len, consumerir_freq_range_t *ranges)
+{
+ size_t to_copy = ARRAY_SIZE(consumerir_freqs);
+
+ to_copy = len < to_copy ? len : to_copy;
+ memcpy(ranges, consumerir_freqs, to_copy * sizeof(consumerir_freq_range_t));
+ return to_copy;
+}
+
+static int consumerir_close(hw_device_t *dev)
+{
+ free(dev);
+ return 0;
+}
+
+/*
+ * Generic device handling
+ */
+static int consumerir_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ if (strcmp(name, CONSUMERIR_TRANSMITTER) != 0) {
+ return -EINVAL;
+ }
+ if (device == NULL) {
+ ALOGE("NULL device on open");
+ return -EINVAL;
+ }
+
+ consumerir_device_t *dev = malloc(sizeof(consumerir_device_t));
+ memset(dev, 0, sizeof(consumerir_device_t));
+
+ dev->common.tag = HARDWARE_DEVICE_TAG;
+ dev->common.version = 0;
+ dev->common.module = (struct hw_module_t*) module;
+ dev->common.close = consumerir_close;
+
+ dev->transmit = consumerir_transmit;
+ dev->get_num_carrier_freqs = consumerir_get_num_carrier_freqs;
+ dev->get_carrier_freqs = consumerir_get_carrier_freqs;
+
+ *device = (hw_device_t*) dev;
+ return 0;
+}
+
+static struct hw_module_methods_t consumerir_module_methods = {
+ .open = consumerir_open,
+};
+
+consumerir_module_t HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = CONSUMERIR_MODULE_API_VERSION_1_0,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = CONSUMERIR_HARDWARE_MODULE_ID,
+ .name = "Demo IR HAL",
+ .author = "The Android Open Source Project",
+ .methods = &consumerir_module_methods,
+ },
+};
diff --git a/modules/gralloc/gralloc.cpp b/modules/gralloc/gralloc.cpp
index 03d46d59..f832f35c 100644
--- a/modules/gralloc/gralloc.cpp
+++ b/modules/gralloc/gralloc.cpp
@@ -217,8 +217,6 @@ static int gralloc_alloc(alloc_device_t* dev,
bpp = 3;
break;
case HAL_PIXEL_FORMAT_RGB_565:
- case HAL_PIXEL_FORMAT_RGBA_5551:
- case HAL_PIXEL_FORMAT_RGBA_4444:
case HAL_PIXEL_FORMAT_RAW_SENSOR:
bpp = 2;
break;
diff --git a/tests/camera2/Android.mk b/tests/camera2/Android.mk
index 8f2278a4..9efac0fa 100644
--- a/tests/camera2/Android.mk
+++ b/tests/camera2/Android.mk
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
CameraStreamTests.cpp \
CameraFrameTests.cpp \
CameraBurstTests.cpp \
+ CameraMultiStreamTests.cpp\
ForkedTests.cpp \
TestForkerEventListener.cpp \
TestSettings.cpp \
diff --git a/tests/camera2/CameraBurstTests.cpp b/tests/camera2/CameraBurstTests.cpp
index 5c4b6e7f..7301fce3 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
@@ -37,12 +38,21 @@
#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
#define dout if (0) std::cout
#endif
+#define WARN_UNLESS(condition) (!(condition) ? (std::cerr) : (std::ostream(NULL)) << "Warning: ")
+#define WARN_LE(exp, act) WARN_UNLESS((exp) <= (act))
+#define WARN_LT(exp, act) WARN_UNLESS((exp) < (act))
+#define WARN_GT(exp, act) WARN_UNLESS((exp) > (act))
+
using namespace android;
using namespace android::camera2;
@@ -122,6 +132,23 @@ public:
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) {
@@ -161,7 +188,7 @@ TEST_F(CameraBurstTest, ManualExposureControl) {
ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
&previewRequest));
{
- Vector<uint8_t> outputStreamIds;
+ Vector<int32_t> outputStreamIds;
outputStreamIds.push(mStreamId);
ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreamIds));
@@ -251,10 +278,447 @@ TEST_F(CameraBurstTest, ManualExposureControl) {
dout << "max doubling count: " << max_doubling_count << std::endl;
- EXPECT_LE(CAMERA_EXPOSURE_DOUBLING_COUNT, max_doubling_count)
- << "average brightness should double at least "
- << CAMERA_EXPOSURE_DOUBLING_COUNT
- << " times over each consecutive frame as the exposure is doubled";
+ /**
+ * Make this check warning only, since the brightness calculation is not reliable
+ * and we have separate test to cover this case. Plus it is pretty subtle to make
+ * it right without complicating the test too much.
+ */
+ WARN_LE(CAMERA_EXPOSURE_DOUBLING_COUNT, max_doubling_count)
+ << "average brightness should double at least "
+ << CAMERA_EXPOSURE_DOUBLING_COUNT
+ << " times over each consecutive frame as the exposure is doubled"
+ << std::endl;
+}
+
+/**
+ * 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
+ }
+ }
+
+ camera_metadata_ro_entry hardwareLevel =
+ GetStaticEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
+ ASSERT_EQ(1u, hardwareLevel.count);
+ uint8_t level = hardwareLevel.data.u8[0];
+ ASSERT_GE(level, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
+ ASSERT_LE(level, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
+ if (level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ std::cerr << "Skipping test "
+ << test_info->test_case_name() << "."
+ << test_info->name()
+ << " because HAL hardware supported level is limited "
+ << std::endl;
+ return;
+ }
+
+ 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) {
+ ASSERT_GT(sensivityRange.data.i32[0], 0);
+ ASSERT_GT(sensivityRange.data.i32[1], 0);
+ 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(maxDuration, 0) << "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<int32_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 ) {
+ WARN_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] <<
+ std::endl;
+ }
+ // 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];
+ WARN_LT(timeDelta, expectedDelta + DURATION_UPPER_BOUND) <<
+ "Capture took " << timeDelta << " ns to receive, but expected"
+ " frame duration was " << expectedDelta << " ns." <<
+ std::endl;
+ WARN_GT(timeDelta, expectedDelta - DURATION_LOWER_BOUND) <<
+ "Capture took " << timeDelta << " ns to receive, but expected"
+ " frame duration was " << expectedDelta << " ns." <<
+ std::endl;
+ 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 84450984..e78a862c 100644
--- a/tests/camera2/CameraFrameTests.cpp
+++ b/tests/camera2/CameraFrameTests.cpp
@@ -23,9 +23,8 @@
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "CameraDeviceBase.h"
-#include "utils/StrongPointer.h"
-
+#include <common/CameraDeviceBase.h>
+#include <utils/StrongPointer.h>
#include <gui/CpuConsumer.h>
#include <gui/Surface.h>
@@ -91,7 +90,7 @@ TEST_P(CameraFrameTest, GetFrame) {
ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
&previewRequest));
{
- Vector<uint8_t> outputStreamIds;
+ Vector<int32_t> outputStreamIds;
outputStreamIds.push(mStreamId);
ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreamIds));
diff --git a/tests/camera2/CameraMetadataTests.cpp b/tests/camera2/CameraMetadataTests.cpp
index 66c4847d..eddc5930 100644
--- a/tests/camera2/CameraMetadataTests.cpp
+++ b/tests/camera2/CameraMetadataTests.cpp
@@ -25,7 +25,7 @@
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "CameraDeviceBase.h"
+#include "common/CameraDeviceBase.h"
#include "utils/StrongPointer.h"
#include <gui/CpuConsumer.h>
@@ -136,10 +136,6 @@ TEST_F(CameraMetadataTest, RequiredFormats) {
EXPECT_TRUE(
HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED));
-
- EXPECT_TRUE(
- HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
HAL_PIXEL_FORMAT_BLOB)); // JPEG
if (getDeviceVersion() < CAMERA_DEVICE_API_VERSION_3_0) {
@@ -169,9 +165,11 @@ TEST_F(CameraMetadataTest, SaneResolutions) {
// Iff there are listed raw resolutions, the format should be available
int rawResolutionsCount =
GetEntryCountFromStaticTag(ANDROID_SCALER_AVAILABLE_RAW_SIZES);
- EXPECT_EQ(rawResolutionsCount > 0,
- HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
- HAL_PIXEL_FORMAT_RAW_SENSOR));
+ if (rawResolutionsCount > 0) {
+ EXPECT_TRUE(
+ HasElementInArrayFromStaticTag(ANDROID_SCALER_AVAILABLE_FORMATS,
+ HAL_PIXEL_FORMAT_RAW_SENSOR));
+ }
// Required processed sizes.
int processedSizeCount =
diff --git a/tests/camera2/CameraModuleFixture.h b/tests/camera2/CameraModuleFixture.h
index ef4a9a52..acf41e10 100644
--- a/tests/camera2/CameraModuleFixture.h
+++ b/tests/camera2/CameraModuleFixture.h
@@ -22,8 +22,9 @@
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "Camera2Device.h"
-#include "Camera3Device.h"
+#include <device2/Camera2Device.h>
+#include <device3/Camera3Device.h>
+
#include "camera2_utils.h"
#include "TestExtensions.h"
diff --git a/tests/camera2/CameraModuleTests.cpp b/tests/camera2/CameraModuleTests.cpp
index 44d3e3bf..ae4267b8 100644
--- a/tests/camera2/CameraModuleTests.cpp
+++ b/tests/camera2/CameraModuleTests.cpp
@@ -19,12 +19,12 @@
#define LOG_TAG "CameraModuleTest"
#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <common/CameraDeviceBase.h>
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "CameraDeviceBase.h"
-#include "utils/StrongPointer.h"
#include "CameraModuleFixture.h"
namespace android {
@@ -78,17 +78,19 @@ TEST_F(CameraModuleTest, LoadModuleBadIndices) {
TEST_EXTENSION_FORKING_INIT;
int idx[] = { -1, mNumberOfCameras, mNumberOfCameras + 1 };
+ hw_device_t *device = NULL;
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);
- EXPECT_EQ(-ENODEV, deviceInitializeCode)
- << "Incorrect error code when trying to initialize invalid index "
- << idx[i];
- mDevice.clear();
+ String8 deviceName = String8::format("%d", idx[i]);
+ status_t res =
+ mModule->common.methods->open(
+ &mModule->common,
+ deviceName,
+ &device);
+ EXPECT_NE(OK, res);
+ EXPECT_EQ(-ENODEV, res)
+ << "Incorrect error code when trying to open camera with invalid id "
+ << deviceName;
}
}
diff --git a/tests/camera2/CameraMultiStreamTests.cpp b/tests/camera2/CameraMultiStreamTests.cpp
new file mode 100644
index 00000000..de1cfd6f
--- /dev/null
+++ b/tests/camera2/CameraMultiStreamTests.cpp
@@ -0,0 +1,683 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "CameraMultiStreamTest"
+//#define LOG_NDEBUG 0
+#include "CameraStreamFixture.h"
+#include "TestExtensions.h"
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <common/CameraDeviceBase.h>
+#include <hardware/hardware.h>
+#include <hardware/camera2.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
+
+#define DEFAULT_FRAME_DURATION 33000000LL // 33ms
+#define CAMERA_HEAP_COUNT 1
+#define CAMERA_EXPOSURE_FORMAT CAMERA_STREAM_AUTO_CPU_FORMAT
+#define CAMERA_DISPLAY_FORMAT HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
+#define CAMERA_MULTI_STREAM_DEBUGGING 0
+#define CAMERA_FRAME_TIMEOUT 1000000000LL // nsecs (1 secs)
+#define PREVIEW_RENDERING_TIME_INTERVAL 200000 // in unit of us, 200ms
+#define TOLERANCE_MARGIN 0.01 // 1% tolerance margin for exposure sanity check.
+/* constants for display */
+#define DISPLAY_BUFFER_HEIGHT 1024
+#define DISPLAY_BUFFER_WIDTH 1024
+#define DISPLAY_BUFFER_FORMAT PIXEL_FORMAT_RGB_888
+
+// This test intends to test large preview size but less than 1080p.
+#define PREVIEW_WIDTH_CAP 1920
+#define PREVIEW_HEIGHT_CAP 1080
+// This test intends to test small metering burst size that is less than 640x480
+#define METERING_WIDTH_CAP 640
+#define METERING_HEIGHT_CAP 480
+
+#define EXP_WAIT_MULTIPLIER 2
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+static const CameraStreamParams DEFAULT_STREAM_PARAMETERS = {
+ /*mFormat*/ CAMERA_EXPOSURE_FORMAT,
+ /*mHeapCount*/ CAMERA_HEAP_COUNT
+};
+
+static const CameraStreamParams DISPLAY_STREAM_PARAMETERS = {
+ /*mFormat*/ CAMERA_DISPLAY_FORMAT,
+ /*mHeapCount*/ CAMERA_HEAP_COUNT
+};
+
+class CameraMultiStreamTest
+ : public ::testing::Test,
+ public CameraStreamFixture {
+
+public:
+ CameraMultiStreamTest() : CameraStreamFixture(DEFAULT_STREAM_PARAMETERS) {
+ TEST_EXTENSION_FORKING_CONSTRUCTOR;
+
+ if (HasFatalFailure()) {
+ return;
+ }
+ /**
+ * Don't create default stream, each test is in charge of creating
+ * its own streams.
+ */
+ }
+
+ ~CameraMultiStreamTest() {
+ TEST_EXTENSION_FORKING_DESTRUCTOR;
+ }
+
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mSurfaceControl;
+
+ void CreateOnScreenSurface(sp<ANativeWindow>& surface) {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ mSurfaceControl = mComposerClient->createSurface(
+ String8("CameraMultiStreamTest StreamingImage Surface"),
+ DISPLAY_BUFFER_HEIGHT, DISPLAY_BUFFER_WIDTH,
+ DISPLAY_BUFFER_FORMAT, 0);
+
+ ASSERT_NE((void*)NULL, mSurfaceControl.get());
+ ASSERT_TRUE(mSurfaceControl->isValid());
+
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ surface = mSurfaceControl->getSurface();
+
+ ASSERT_NE((void*)NULL, surface.get());
+ }
+
+ struct Size {
+ int32_t width;
+ int32_t height;
+ };
+
+ // Select minimal size by number of pixels.
+ void GetMinSize(const int32_t* data, size_t count,
+ Size* min, int32_t* idx) {
+ ASSERT_NE((int32_t*)NULL, data);
+ int32_t minIdx = 0;
+ int32_t minSize = INT_MAX, tempSize;
+ for (size_t i = 0; i < count; i+=2) {
+ tempSize = data[i] * data[i+1];
+ if (minSize > tempSize) {
+ minSize = tempSize;
+ minIdx = i;
+ }
+ }
+ min->width = data[minIdx];
+ min->height = data[minIdx + 1];
+ *idx = minIdx;
+ }
+
+ // Select maximal size by number of pixels.
+ void GetMaxSize(const int32_t* data, size_t count,
+ Size* max, int32_t* idx) {
+ ASSERT_NE((int32_t*)NULL, data);
+ int32_t maxIdx = 0;
+ int32_t maxSize = INT_MIN, tempSize;
+ for (size_t i = 0; i < count; i+=2) {
+ tempSize = data[i] * data[i+1];
+ if (maxSize < tempSize) {
+ maxSize = tempSize;
+ maxIdx = i;
+ }
+ }
+ max->width = data[maxIdx];
+ max->height = data[maxIdx + 1];
+ *idx = maxIdx;
+ }
+
+ // Cap size by number of pixels.
+ Size CapSize(Size cap, Size input) {
+ if (input.width * input.height > cap.width * cap.height) {
+ return cap;
+ }
+ return input;
+ }
+
+ struct CameraStream : public RefBase {
+
+ public:
+ /**
+ * Only initialize the variables here, do the ASSERT check in
+ * SetUp function. To make this stream useful, the SetUp must
+ * be called before using it.
+ */
+ CameraStream(
+ int width,
+ int height,
+ const sp<CameraDeviceBase>& device,
+ CameraStreamParams param, sp<ANativeWindow> surface,
+ bool useCpuConsumer)
+ : mDevice(device),
+ mWidth(width),
+ mHeight(height) {
+ mFormat = param.mFormat;
+ if (useCpuConsumer) {
+ sp<BufferQueue> bq = new BufferQueue();
+ mCpuConsumer = new CpuConsumer(bq, param.mHeapCount);
+ mCpuConsumer->setName(String8(
+ "CameraMultiStreamTest::mCpuConsumer"));
+ mNativeWindow = new Surface(bq);
+ } else {
+ // Render the stream to screen.
+ mCpuConsumer = NULL;
+ mNativeWindow = surface;
+ }
+
+ mFrameListener = new FrameListener();
+ if (mCpuConsumer != 0) {
+ mCpuConsumer->setFrameAvailableListener(mFrameListener);
+ }
+ }
+
+ /**
+ * Finally create camera stream, and do the ASSERT check, since we
+ * can not do it in ctor.
+ */
+ void SetUp() {
+ ASSERT_EQ(OK,
+ mDevice->createStream(mNativeWindow,
+ mWidth, mHeight, mFormat, /*size (for jpegs)*/0,
+ &mStreamId));
+
+ ASSERT_NE(-1, mStreamId);
+ }
+
+ int GetStreamId() { return mStreamId; }
+ sp<CpuConsumer> GetConsumer() { return mCpuConsumer; }
+ sp<FrameListener> GetFrameListener() { return mFrameListener; }
+
+ protected:
+ ~CameraStream() {
+ if (mDevice.get()) {
+ mDevice->waitUntilDrained();
+ mDevice->deleteStream(mStreamId);
+ }
+ // Clear producer before consumer.
+ mNativeWindow.clear();
+ mCpuConsumer.clear();
+ }
+
+ private:
+ sp<FrameListener> mFrameListener;
+ sp<CpuConsumer> mCpuConsumer;
+ sp<ANativeWindow> mNativeWindow;
+ sp<CameraDeviceBase> mDevice;
+ int mStreamId;
+ int mWidth;
+ int mHeight;
+ int mFormat;
+ };
+
+ int64_t GetExposureValue(const CameraMetadata& metaData) {
+ camera_metadata_ro_entry_t entry =
+ metaData.find(ANDROID_SENSOR_EXPOSURE_TIME);
+ EXPECT_EQ(1u, entry.count);
+ if (entry.count == 1) {
+ return entry.data.i64[0];
+ }
+ return -1;
+ }
+
+ int32_t GetSensitivity(const CameraMetadata& metaData) {
+ camera_metadata_ro_entry_t entry =
+ metaData.find(ANDROID_SENSOR_SENSITIVITY);
+ EXPECT_EQ(1u, entry.count);
+ if (entry.count == 1) {
+ return entry.data.i32[0];
+ }
+ return -1;
+ }
+
+ int64_t GetFrameDuration(const CameraMetadata& metaData) {
+ camera_metadata_ro_entry_t entry =
+ metaData.find(ANDROID_SENSOR_FRAME_DURATION);
+ EXPECT_EQ(1u, entry.count);
+ if (entry.count == 1) {
+ return entry.data.i64[0];
+ }
+ return -1;
+ }
+
+ void CreateRequests(CameraMetadata& previewRequest,
+ CameraMetadata& meteringRequest,
+ CameraMetadata& captureRequest,
+ int previewStreamId,
+ int meteringStreamId,
+ int captureStreamId) {
+ int32_t requestId = 0;
+ Vector<int32_t> previewStreamIds;
+ previewStreamIds.push(previewStreamId);
+ ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ &previewRequest));
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+ previewStreamIds));
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_ID,
+ &requestId, 1));
+
+ // Create metering request, manual settings
+ // Manual control: Disable 3A, noise reduction, edge sharping
+ uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+ uint8_t nrOff = static_cast<uint8_t>(ANDROID_NOISE_REDUCTION_MODE_OFF);
+ uint8_t sharpOff = static_cast<uint8_t>(ANDROID_EDGE_MODE_OFF);
+ Vector<int32_t> meteringStreamIds;
+ meteringStreamIds.push(meteringStreamId);
+ ASSERT_EQ(OK, mDevice->createDefaultRequest(
+ CAMERA2_TEMPLATE_PREVIEW,
+ &meteringRequest));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ meteringStreamIds));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_CONTROL_MODE,
+ &cmOff, 1));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_NOISE_REDUCTION_MODE,
+ &nrOff, 1));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_EDGE_MODE,
+ &sharpOff, 1));
+
+ // Create capture request, manual settings
+ Vector<int32_t> captureStreamIds;
+ captureStreamIds.push(captureStreamId);
+ ASSERT_EQ(OK, mDevice->createDefaultRequest(
+ CAMERA2_TEMPLATE_PREVIEW,
+ &captureRequest));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ captureStreamIds));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_CONTROL_MODE,
+ &cmOff, 1));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_NOISE_REDUCTION_MODE,
+ &nrOff, 1));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_EDGE_MODE,
+ &sharpOff, 1));
+ }
+
+ sp<CameraStream> CreateStream(
+ int width,
+ int height,
+ const sp<CameraDeviceBase>& device,
+ CameraStreamParams param = DEFAULT_STREAM_PARAMETERS,
+ sp<ANativeWindow> surface = NULL,
+ bool useCpuConsumer = true) {
+ param.mFormat = MapAutoFormat(param.mFormat);
+ return new CameraStream(width, height, device,
+ param, surface, useCpuConsumer);
+ }
+
+ void CaptureBurst(CameraMetadata& request, size_t requestCount,
+ const Vector<int64_t>& exposures,
+ const Vector<int32_t>& sensitivities,
+ const sp<CameraStream>& stream,
+ int64_t minFrameDuration,
+ int32_t* requestIdStart) {
+ ASSERT_EQ(OK, request.update(ANDROID_SENSOR_FRAME_DURATION,
+ &minFrameDuration, 1));
+ // Submit a series of requests with the specified exposure/gain values.
+ int32_t targetRequestId = *requestIdStart;
+ for (size_t i = 0; i < requestCount; i++) {
+ ASSERT_EQ(OK, request.update(ANDROID_REQUEST_ID, requestIdStart, 1));
+ ASSERT_EQ(OK, request.update(ANDROID_SENSOR_EXPOSURE_TIME, &exposures[i], 1));
+ ASSERT_EQ(OK, request.update(ANDROID_SENSOR_SENSITIVITY, &sensitivities[i], 1));
+ ASSERT_EQ(OK, mDevice->capture(request));
+ ALOGV("Submitting request with: id %d with exposure %lld, sensitivity %d",
+ *requestIdStart, exposures[i], sensitivities[i]);
+ if (CAMERA_MULTI_STREAM_DEBUGGING) {
+ request.dump(STDOUT_FILENO);
+ }
+ (*requestIdStart)++;
+ }
+ // Get capture burst results.
+ Vector<nsecs_t> captureBurstTimes;
+ sp<CpuConsumer> consumer = stream->GetConsumer();
+ sp<FrameListener> listener = stream->GetFrameListener();
+
+ // Set wait limit based on expected frame duration.
+ int64_t waitLimit = CAMERA_FRAME_TIMEOUT;
+ for (size_t i = 0; i < requestCount; i++) {
+ ALOGV("Reading request result %d", i);
+
+ /**
+ * Raise the timeout to be at least twice as long as the exposure
+ * time. to avoid a false positive when the timeout is too short.
+ */
+ if ((exposures[i] * EXP_WAIT_MULTIPLIER) > waitLimit) {
+ waitLimit = exposures[i] * EXP_WAIT_MULTIPLIER;
+ }
+
+ CameraMetadata frameMetadata;
+ int32_t resultRequestId;
+ do {
+ ASSERT_EQ(OK, mDevice->waitForNextFrame(waitLimit));
+ ASSERT_EQ(OK, mDevice->getNextFrame(&frameMetadata));
+
+ camera_metadata_entry_t resultEntry = frameMetadata.find(ANDROID_REQUEST_ID);
+ ASSERT_EQ(1u, resultEntry.count);
+ resultRequestId = resultEntry.data.i32[0];
+ if (CAMERA_MULTI_STREAM_DEBUGGING) {
+ std::cout << "capture result req id: " << resultRequestId << std::endl;
+ }
+ } while (resultRequestId != targetRequestId);
+ targetRequestId++;
+ ALOGV("Got capture burst result for request %d", i);
+
+ // Validate capture result
+ if (CAMERA_MULTI_STREAM_DEBUGGING) {
+ frameMetadata.dump(STDOUT_FILENO);
+ }
+
+ // TODO: Need revisit it to figure out an accurate margin.
+ int64_t resultExposure = GetExposureValue(frameMetadata);
+ int32_t resultSensitivity = GetSensitivity(frameMetadata);
+ EXPECT_LE(sensitivities[i] * (1.0 - TOLERANCE_MARGIN), resultSensitivity);
+ EXPECT_GE(sensitivities[i] * (1.0 + TOLERANCE_MARGIN), resultSensitivity);
+ EXPECT_LE(exposures[i] * (1.0 - TOLERANCE_MARGIN), resultExposure);
+ EXPECT_GE(exposures[i] * (1.0 + TOLERANCE_MARGIN), resultExposure);
+
+ ASSERT_EQ(OK, listener->waitForFrame(waitLimit));
+ captureBurstTimes.push_back(systemTime());
+ CpuConsumer::LockedBuffer imgBuffer;
+ ASSERT_EQ(OK, consumer->lockNextBuffer(&imgBuffer));
+ ALOGV("Got capture buffer for request %d", i);
+
+ /**
+ * TODO: Validate capture buffer. Current brightness calculation
+ * is too slow, it also doesn't account for saturation effects,
+ * which is quite common since we are going over a significant
+ * range of EVs. we need figure out some reliable way to validate
+ * buffer data.
+ */
+
+ ASSERT_EQ(OK, consumer->unlockBuffer(imgBuffer));
+ if (i > 0) {
+ nsecs_t timeDelta =
+ captureBurstTimes[i] - captureBurstTimes[i-1];
+ EXPECT_GE(timeDelta, exposures[i]);
+ }
+ }
+ }
+
+ /**
+ * Intentionally shadow default CreateStream function from base class,
+ * because we don't want any test in this class to use the default
+ * stream creation function.
+ */
+ void CreateStream() {
+ }
+};
+
+/**
+ * This test adds multiple stream use case test, basically, test 3
+ * streams:
+ *
+ * 1. Preview stream, with large size that is no bigger than 1080p
+ * we render this stream to display and vary the exposure time for
+ * for certain amount of time for visualization purpose.
+ *
+ * 2. Metering stream, with small size that is no bigger than VGA size.
+ * a burst is issued for different exposure times and analog gains
+ * (or analog gain implemented sensitivities) then check if the capture
+ * result metadata matches the request.
+ *
+ * 3. Capture stream, this is basically similar as meterting stream, but
+ * has large size, which is the largest supported JPEG capture size.
+ *
+ * This multiple stream test is to test if HAL supports:
+ *
+ * 1. Multiple streams like above, HAL should support at least 3 streams
+ * concurrently: one preview stream, 2 other YUV stream.
+ *
+ * 2. Manual control(gain/exposure) of mutiple burst capture.
+ */
+TEST_F(CameraMultiStreamTest, MultiBurst) {
+
+ TEST_EXTENSION_FORKING_INIT;
+
+ camera_metadata_ro_entry availableProcessedSizes =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+ ASSERT_EQ(0u, availableProcessedSizes.count % 2);
+ ASSERT_GE(availableProcessedSizes.count, 2u);
+ camera_metadata_ro_entry availableProcessedMinFrameDurations =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS);
+ EXPECT_EQ(availableProcessedSizes.count,
+ availableProcessedMinFrameDurations.count * 2);
+
+ camera_metadata_ro_entry availableJpegSizes =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+ ASSERT_EQ(0u, availableJpegSizes.count % 2);
+ ASSERT_GE(availableJpegSizes.count, 2u);
+
+ camera_metadata_ro_entry hardwareLevel =
+ GetStaticEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
+ ASSERT_EQ(1u, hardwareLevel.count);
+ uint8_t level = hardwareLevel.data.u8[0];
+ ASSERT_GE(level, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
+ ASSERT_LE(level, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
+ if (level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ std::cerr << "Skipping test "
+ << test_info->test_case_name() << "."
+ << test_info->name()
+ << " because HAL hardware supported level is limited "
+ << std::endl;
+ return;
+ }
+
+ // Find the right sizes for preview, metering, and capture streams
+ // assumes at least 2 entries in availableProcessedSizes.
+ int64_t minFrameDuration = DEFAULT_FRAME_DURATION;
+ Size processedMinSize, processedMaxSize, jpegMaxSize;
+ const int32_t* data = availableProcessedSizes.data.i32;
+ size_t count = availableProcessedSizes.count;
+
+ int32_t minIdx, maxIdx;
+ GetMinSize(data, count, &processedMinSize, &minIdx);
+ GetMaxSize(data, count, &processedMaxSize, &maxIdx);
+ ALOGV("Found processed max size: %dx%d, min size = %dx%d",
+ processedMaxSize.width, processedMaxSize.height,
+ processedMinSize.width, processedMinSize.height);
+
+ if (availableProcessedSizes.count ==
+ availableProcessedMinFrameDurations.count * 2) {
+ minFrameDuration =
+ availableProcessedMinFrameDurations.data.i64[maxIdx / 2];
+ }
+
+ EXPECT_GT(minFrameDuration, 0);
+
+ if (minFrameDuration <= 0) {
+ minFrameDuration = DEFAULT_FRAME_DURATION;
+ }
+
+ ALOGV("targeted minimal frame duration is: %lldns", minFrameDuration);
+
+ data = &(availableJpegSizes.data.i32[0]);
+ count = availableJpegSizes.count;
+ GetMaxSize(data, count, &jpegMaxSize, &maxIdx);
+ ALOGV("Found Jpeg size max idx = %d", maxIdx);
+
+ // Max Jpeg size should be available in processed sizes. Use it for
+ // YUV capture anyway.
+ EXPECT_EQ(processedMaxSize.width, jpegMaxSize.width);
+ EXPECT_EQ(processedMaxSize.height, jpegMaxSize.height);
+
+ // Cap preview size.
+ Size previewLimit = { PREVIEW_WIDTH_CAP, PREVIEW_HEIGHT_CAP };
+ // FIXME: need make sure the previewLimit is supported by HAL.
+ Size previewSize = CapSize(previewLimit, processedMaxSize);
+ // Cap Metering size.
+ Size meteringLimit = { METERING_WIDTH_CAP, METERING_HEIGHT_CAP };
+ // Cap metering size to VGA (VGA is mandatory by CDD)
+ Size meteringSize = CapSize(meteringLimit, processedMinSize);
+ // Capture stream should be the max size of jpeg sizes.
+ ALOGV("preview size: %dx%d, metering size: %dx%d, capture size: %dx%d",
+ previewSize.width, previewSize.height,
+ meteringSize.width, meteringSize.height,
+ jpegMaxSize.width, jpegMaxSize.height);
+
+ // Create streams
+ // Preview stream: small resolution, render on the screen.
+ sp<CameraStream> previewStream;
+ {
+ sp<ANativeWindow> surface;
+ ASSERT_NO_FATAL_FAILURE(CreateOnScreenSurface(/*out*/surface));
+ previewStream = CreateStream(
+ previewSize.width,
+ previewSize.height,
+ mDevice,
+ DISPLAY_STREAM_PARAMETERS,
+ surface,
+ false);
+ ASSERT_NE((void*)NULL, previewStream.get());
+ ASSERT_NO_FATAL_FAILURE(previewStream->SetUp());
+ }
+ // Metering burst stream: small resolution yuv stream
+ sp<CameraStream> meteringStream =
+ CreateStream(
+ meteringSize.width,
+ meteringSize.height,
+ mDevice);
+ ASSERT_NE((void*)NULL, meteringStream.get());
+ ASSERT_NO_FATAL_FAILURE(meteringStream->SetUp());
+ // Capture burst stream: full resolution yuv stream
+ sp<CameraStream> captureStream =
+ CreateStream(
+ jpegMaxSize.width,
+ jpegMaxSize.height,
+ mDevice);
+ ASSERT_NE((void*)NULL, captureStream.get());
+ ASSERT_NO_FATAL_FAILURE(captureStream->SetUp());
+
+ // Create Preview request.
+ CameraMetadata previewRequest, meteringRequest, captureRequest;
+ ASSERT_NO_FATAL_FAILURE(CreateRequests(previewRequest, meteringRequest,
+ captureRequest, previewStream->GetStreamId(),
+ meteringStream->GetStreamId(), captureStream->GetStreamId()));
+
+ // Start preview
+ if (CAMERA_MULTI_STREAM_DEBUGGING) {
+ previewRequest.dump(STDOUT_FILENO);
+ }
+
+ // Generate exposure and sensitivity lists
+ camera_metadata_ro_entry exposureTimeRange =
+ GetStaticEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE);
+ ASSERT_EQ(exposureTimeRange.count, 2u);
+ int64_t minExp = exposureTimeRange.data.i64[0];
+ int64_t maxExp = exposureTimeRange.data.i64[1];
+ ASSERT_GT(maxExp, minExp);
+
+ camera_metadata_ro_entry sensivityRange =
+ GetStaticEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE);
+ ASSERT_EQ(2u, sensivityRange.count);
+ int32_t minSensitivity = sensivityRange.data.i32[0];
+ int32_t maxSensitivity = sensivityRange.data.i32[1];
+ camera_metadata_ro_entry maxAnalogSenEntry =
+ GetStaticEntry(ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY);
+ EXPECT_EQ(1u, maxAnalogSenEntry.count);
+ int32_t maxAnalogSensitivity = maxAnalogSenEntry.data.i32[0];
+ EXPECT_LE(maxAnalogSensitivity, maxSensitivity);
+ // Only test the sensitivity implemented by analog gain.
+ if (maxAnalogSensitivity > maxSensitivity) {
+ // Fallback to maxSensitity
+ maxAnalogSensitivity = maxSensitivity;
+ }
+
+ // sensitivity list, only include the sensitivities that are implemented
+ // purely by analog gain if possible.
+ Vector<int32_t> sensitivities;
+ Vector<int64_t> exposures;
+ count = (maxAnalogSensitivity - minSensitivity + 99) / 100;
+ sensitivities.push_back(minSensitivity);
+ for (size_t i = 1; i < count; i++) {
+ sensitivities.push_back(minSensitivity + i * 100);
+ }
+ sensitivities.push_back(maxAnalogSensitivity);
+ ALOGV("Sensitivity Range: min=%d, max=%d", minSensitivity,
+ maxAnalogSensitivity);
+ int64_t exp = minExp;
+ while (exp < maxExp) {
+ exposures.push_back(exp);
+ exp *= 2;
+ }
+ // Sweep the exposure value for preview, just for visual inspection purpose.
+ uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+ for (size_t i = 0; i < exposures.size(); i++) {
+ ASSERT_EQ(OK, previewRequest.update(
+ ANDROID_CONTROL_MODE,
+ &cmOff, 1));
+ ASSERT_EQ(OK, previewRequest.update(
+ ANDROID_SENSOR_EXPOSURE_TIME,
+ &exposures[i], 1));
+ ALOGV("Submitting preview request %d with exposure %lld",
+ i, exposures[i]);
+
+ ASSERT_EQ(OK, mDevice->setStreamingRequest(previewRequest));
+
+ // Let preview run 200ms on screen for each exposure time.
+ usleep(PREVIEW_RENDERING_TIME_INTERVAL);
+ }
+
+ size_t requestCount = sensitivities.size();
+ if (requestCount > exposures.size()) {
+ requestCount = exposures.size();
+ }
+
+ // To maintain the request id uniqueness (preview request id is 0), make burst capture start
+ // request id 1 here.
+ int32_t requestIdStart = 1;
+ /**
+ * Submit metering request, set default frame duration to minimal possible
+ * value, we want the capture to run as fast as possible. HAL should adjust
+ * the frame duration to minimal necessary value to support the requested
+ * exposure value if exposure is larger than frame duration.
+ */
+ CaptureBurst(meteringRequest, requestCount, exposures, sensitivities,
+ meteringStream, minFrameDuration, &requestIdStart);
+
+ /**
+ * Submit capture request, set default frame duration to minimal possible
+ * value, we want the capture to run as fast as possible. HAL should adjust
+ * the frame duration to minimal necessary value to support the requested
+ * exposure value if exposure is larger than frame duration.
+ */
+ CaptureBurst(captureRequest, requestCount, exposures, sensitivities,
+ captureStream, minFrameDuration, &requestIdStart);
+
+ ASSERT_EQ(OK, mDevice->clearStreamingRequest());
+}
+
+}
+}
+}
diff --git a/tests/camera2/CameraStreamFixture.h b/tests/camera2/CameraStreamFixture.h
index a4dc4a81..a1f3aae8 100644
--- a/tests/camera2/CameraStreamFixture.h
+++ b/tests/camera2/CameraStreamFixture.h
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include <iostream>
+#include <fstream>
#include <gui/CpuConsumer.h>
#include <gui/Surface.h>
@@ -29,6 +30,8 @@
#include "CameraModuleFixture.h"
#include "TestExtensions.h"
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
namespace android {
namespace camera2 {
namespace tests {
@@ -90,7 +93,6 @@ private:
CameraModuleFixture::SetUp();
- CameraStreamParams p = mParam;
sp<CameraDeviceBase> device = mDevice;
/* use an arbitrary w,h */
@@ -159,11 +161,11 @@ protected:
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());
+ mNativeWindow = new Surface(bq);
int format = MapAutoFormat(p.mFormat);
@@ -194,6 +196,80 @@ protected:
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 164e0e54..69ee274d 100644
--- a/tests/camera2/CameraStreamTests.cpp
+++ b/tests/camera2/CameraStreamTests.cpp
@@ -25,12 +25,12 @@
#include "hardware/hardware.h"
#include "hardware/camera2.h"
-#include "Camera2Device.h"
-#include "utils/StrongPointer.h"
-
+#include <utils/StrongPointer.h>
#include <gui/CpuConsumer.h>
#include <gui/Surface.h>
+#include <device2/Camera2Device.h>
+
#include "CameraStreamFixture.h"
#include "TestExtensions.h"
diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp
index 92ef2212..600d4404 100644
--- a/tests/camera2/camera2.cpp
+++ b/tests/camera2/camera2.cpp
@@ -201,7 +201,8 @@ class Camera2Test: public testing::Test {
if (mDevice != NULL) {
closeCameraDevice(&mDevice);
}
- mDevice = openCameraDevice(id);
+ mId = id;
+ mDevice = openCameraDevice(mId);
ASSERT_TRUE(NULL != mDevice) << "Failed to open camera device";
camera_info info;
@@ -334,6 +335,7 @@ class Camera2Test: public testing::Test {
TearDownModule();
}
+ int mId;
camera2_device *mDevice;
const camera_metadata_t *mStaticInfo;
@@ -386,7 +388,8 @@ TEST_F(Camera2Test, Capture1Raw) {
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);
@@ -417,8 +420,7 @@ TEST_F(Camera2Test, Capture1Raw) {
int streamId;
ASSERT_NO_FATAL_FAILURE(
- setUpStream(rawConsumer->getProducerInterface(),
- width, height, format, &streamId) );
+ setUpStream(bq, width, height, format, &streamId) );
camera_metadata_t *request;
request = allocate_camera_metadata(20, 2000);
@@ -520,7 +522,8 @@ TEST_F(Camera2Test, CaptureBurstRaw) {
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);
@@ -551,8 +554,7 @@ TEST_F(Camera2Test, CaptureBurstRaw) {
int streamId;
ASSERT_NO_FATAL_FAILURE(
- setUpStream(rawConsumer->getProducerInterface(),
- width, height, format, &streamId) );
+ setUpStream(bq, width, height, format, &streamId) );
camera_metadata_t *request;
request = allocate_camera_metadata(20, 2000);
@@ -701,7 +703,8 @@ TEST_F(Camera2Test, Capture1Jpeg) {
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);
@@ -720,8 +723,7 @@ TEST_F(Camera2Test, Capture1Jpeg) {
int streamId;
ASSERT_NO_FATAL_FAILURE(
- setUpStream(jpegConsumer->getProducerInterface(),
- width, height, format, &streamId) );
+ setUpStream(bq, width, height, format, &streamId) );
camera_metadata_t *request;
request = allocate_camera_metadata(20, 2000);
diff --git a/tests/camera2/camera2_utils.cpp b/tests/camera2/camera2_utils.cpp
index 76a72333..3c0767a3 100644
--- a/tests/camera2/camera2_utils.cpp
+++ b/tests/camera2/camera2_utils.cpp
@@ -210,7 +210,6 @@ int MetadataQueue::consumer_dequeue(const camera2_request_queue_src_ops_t *q,
int MetadataQueue::consumer_free(const camera2_request_queue_src_ops_t *q,
camera_metadata_t *old_buffer) {
- MetadataQueue *queue = getInstance(q);
free_camera_metadata(old_buffer);
return OK;
}
diff --git a/tests/hwc/Android.mk b/tests/hwc/Android.mk
new file mode 100644
index 00000000..4cae9eb1
--- /dev/null
+++ b/tests/hwc/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcnativewindow
+LOCAL_SRC_FILES := cnativewindow.c util.c
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := hwc-test-arrows
+LOCAL_SRC_FILES := test-arrows.c
+LOCAL_STATIC_LIBRARIES := libcnativewindow
+LOCAL_SHARED_LIBRARIES := libEGL libGLESv2 libdl libhardware
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+include $(BUILD_EXECUTABLE)
diff --git a/tests/hwc/cnativewindow.c b/tests/hwc/cnativewindow.c
new file mode 100644
index 00000000..76f45643
--- /dev/null
+++ b/tests/hwc/cnativewindow.c
@@ -0,0 +1,578 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+#include <hardware/hwcomposer.h>
+
+#include <system/window.h>
+#include <cutils/native_handle.h>
+
+// normalize and shorten type names
+typedef struct android_native_base_t aBase;
+typedef struct ANativeWindowBuffer aBuffer;
+typedef struct ANativeWindow aWindow;
+
+static int trace_level = 1;
+
+#define _TRACE(n,fmt...) \
+ do { if (trace_level >= n) fprintf(stderr, "CNW: " fmt); } while (0)
+
+#define ERROR(fmt...) _TRACE(0, fmt)
+#define INFO(fmt...) _TRACE(1, fmt)
+#define LOG(fmt...) _TRACE(2, fmt)
+#define TRACE(fmt...) _TRACE(3, fmt)
+
+#define QCT_WORKAROUND 1
+
+typedef struct CNativeBuffer {
+ aBuffer base;
+ struct CNativeBuffer *next;
+ struct CNativeBuffer *prev;
+ int ffd;
+} CNativeBuffer;
+
+typedef struct CNativeWindow {
+ aWindow base;
+
+ hwc_composer_device_1_t *hwc;
+ framebuffer_device_t *fb;
+ alloc_device_t *gr;
+
+ pthread_mutex_t lock;
+ pthread_cond_t cvar;
+
+ aBuffer *front;
+ aBuffer *spare;
+
+ CNativeBuffer free_buffer_queue;
+
+ unsigned width;
+ unsigned height;
+ unsigned xdpi;
+ unsigned ydpi;
+ unsigned format;
+
+ hwc_display_contents_1_t *dclist[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
+
+ hwc_display_contents_1_t dc;
+ hwc_layer_1_t layer[4];
+} CNativeWindow;
+
+static inline CNativeBuffer *from_abuffer(aBuffer *buf) {
+ return (CNativeBuffer*) buf;
+}
+
+static CNativeBuffer *get_front(struct CNativeBuffer *queue) {
+ CNativeBuffer *buf = queue->next;
+ if (buf == queue)
+ return 0;
+ buf->next->prev = queue;
+ queue->next = buf->next;
+ buf->next = buf->prev = 0;
+ return buf;
+}
+
+static void put_front(struct CNativeBuffer *queue, aBuffer *_buf) {
+ struct CNativeBuffer *buf = (struct CNativeBuffer *) _buf;
+ buf->prev = queue;
+ buf->next = queue->next;
+ queue->next->prev = buf;
+ queue->next = buf;
+}
+
+static void put_back(struct CNativeBuffer *queue, aBuffer *_buf) {
+ struct CNativeBuffer *buf = (struct CNativeBuffer *) _buf;
+ buf->next = queue;
+ buf->prev = queue->prev;
+ queue->prev->next = buf;
+ queue->prev = buf;
+}
+
+static void cnw_inc_ref(aBase *base) { TRACE("buf %p ref++\n",base); }
+static void cnw_dec_ref(aBase *base) { TRACE("buf %p ref--\n",base); }
+
+static inline CNativeWindow *from_base(aWindow *base) {
+ return (CNativeWindow *) base;
+}
+
+static inline CNativeWindow *from_base_const(const aWindow *base) {
+ return (CNativeWindow *) base;
+}
+
+static int cnw_set_swap_interval(aWindow *base, int interval) {
+ CNativeWindow *win = from_base(base);
+ if (win->fb && win->fb->setSwapInterval)
+ return win->fb->setSwapInterval(win->fb, interval);
+ return 0;
+}
+
+static int cnw_dequeue_buffer1(aWindow *base, aBuffer **buf, int *ffd) {
+ CNativeWindow *win = from_base(base);
+ CNativeBuffer *cnb;
+
+ pthread_mutex_lock(&win->lock);
+
+ while ((cnb = get_front(&win->free_buffer_queue)) == 0) {
+ pthread_cond_wait(&win->cvar, &win->lock);
+ }
+
+ *ffd = cnb->ffd;
+ *buf = &cnb->base;
+ cnb->ffd = -1;
+ LOG("<< dequeue buffer %p %d\n", *buf, *ffd);
+
+ pthread_mutex_unlock(&win->lock);
+ return 0;
+}
+
+static int cnw_lock_buffer0(aWindow *base, aBuffer *buffer) {
+ return 0;
+}
+
+static void set_layer(hwc_layer_1_t *dl, aBuffer *buf, int ffd) {
+ int right = buf->width;
+ int bottom = buf->height;
+
+ dl->compositionType = HWC_FRAMEBUFFER;
+ dl->hints = 0;
+ dl->flags = 0;
+
+ dl->handle = buf->handle;
+ dl->transform = 0;
+ dl->blending = HWC_BLENDING_NONE;
+ dl->sourceCrop.left = 0;
+ dl->sourceCrop.top = 0;
+ dl->sourceCrop.right = right;
+ dl->sourceCrop.bottom = bottom;
+ dl->displayFrame.left = 0;
+ dl->displayFrame.top = 0;
+ dl->displayFrame.right = right;
+ dl->displayFrame.bottom = bottom;
+ dl->visibleRegionScreen.numRects = 1;
+ dl->visibleRegionScreen.rects = &dl->displayFrame;
+
+ dl->acquireFenceFd = ffd;
+ dl->releaseFenceFd = -1;
+}
+
+static void hwc_post(CNativeWindow *win, aBuffer *buf, int ffd) {
+ hwc_composer_device_1_t *hwc = win->hwc;
+ hwc_display_contents_1_t *dc = &(win->dc);
+ hwc_layer_1_t *dl = win->dc.hwLayers;
+ int r, i;
+
+ dc->retireFenceFd = -1;
+ dc->outbufAcquireFenceFd = -1;
+ dc->flags = HWC_GEOMETRY_CHANGED;
+ dc->numHwLayers = 1;
+
+ // some hwcomposers fail if these are NULL
+ dc->dpy = (void*) 0xdeadbeef;
+ dc->sur = (void*) 0xdeadbeef;
+
+ set_layer(&dl[0], buf, ffd);
+
+ if (QCT_WORKAROUND) {
+ set_layer(&dl[1], win->spare, -1);
+ dl[1].compositionType = HWC_FRAMEBUFFER_TARGET;
+ dc->numHwLayers++;
+ }
+
+ r = hwc->prepare(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist);
+ if (r) {
+ ERROR("hwc->prepare failed r=%d\n",r);
+ return;
+ }
+
+// for (i = 0; i < dc->numHwLayers; i++)
+// LOG("dl[%d] ctype=0x%08x hints=0x%08x flags=0x%08x\n", i,
+// dl[i].compositionType, dl[0].hints, dl[0].flags);
+
+ r = hwc->set(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist);
+ if (r) {
+ ERROR("hwc->set failed, r=%d\n", r);
+ return;
+ }
+
+ if (dc->retireFenceFd != -1)
+ close(dc->retireFenceFd);
+ if (dl->releaseFenceFd != -1) {
+ CNativeBuffer *cnb = from_abuffer(buf);
+ cnb->ffd = dl->releaseFenceFd;
+ }
+ if (QCT_WORKAROUND)
+ if (dl[1].releaseFenceFd != -1)
+ close(dl[1].releaseFenceFd);
+}
+
+static int cnw_queue_buffer1(aWindow *base, aBuffer *buffer, int ffd) {
+ CNativeWindow *win = from_base(base);
+ int res;
+ LOG(">> queue buffer %p %d\n", buffer, ffd);
+ if (win->fb) {
+ res = win->fb->post(win->fb, buffer->handle);
+ if (ffd != -1)
+ close(ffd);
+ } else {
+ hwc_post(win, buffer, ffd);
+ res = 0;
+ }
+ pthread_mutex_lock(&win->lock);
+ if (win->front)
+ put_back(&win->free_buffer_queue, win->front);
+ win->front = buffer;
+ pthread_cond_signal(&win->cvar);
+ pthread_mutex_unlock(&win->lock);
+
+ return res;
+}
+
+static int cnw_cancel_buffer1(aWindow *base, aBuffer *buf, int ffd) {
+ CNativeWindow *win = from_base(base);
+ CNativeBuffer *cnb = from_abuffer(buf);
+ LOG("<< cancel buffer %p %d\n", buf, ffd);
+ cnb->ffd = ffd;
+ pthread_mutex_lock(&win->lock);
+ put_front(&win->free_buffer_queue, buf);
+ pthread_mutex_unlock(&win->lock);
+ return 0;
+}
+
+static int cnw_dequeue_buffer0(aWindow *base, aBuffer **buf) {
+ int ffd = -1;
+ int r;
+ r = cnw_dequeue_buffer1(base, buf, &ffd);
+ if (ffd != -1)
+ close(ffd);
+ return r;
+}
+
+static int cnw_queue_buffer0(aWindow *base, aBuffer *buf) {
+ return cnw_queue_buffer1(base, buf, -1);
+}
+
+static int cnw_cancel_buffer0(aWindow *base, aBuffer *buf) {
+ return cnw_cancel_buffer1(base, buf, -1);
+}
+
+static int cnw_query(const aWindow *base, int what, int *value) {
+ CNativeWindow *win = from_base_const(base);
+
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ case NATIVE_WINDOW_DEFAULT_WIDTH:
+ *value = win->width;
+ TRACE("query window width: %d\n", *value);
+ return 0;
+ case NATIVE_WINDOW_HEIGHT:
+ case NATIVE_WINDOW_DEFAULT_HEIGHT:
+ *value = win->height;
+ TRACE("query window height: %d\n", *value);
+ return 0;
+ case NATIVE_WINDOW_FORMAT:
+ *value = win->format;
+ TRACE("query window format: %d\n", *value);
+ return 0;
+ case NATIVE_WINDOW_TRANSFORM_HINT:
+ TRACE("query transform hint: 0\n");
+ *value = 0;
+ return 0;
+ case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+ TRACE("query min undequeued buffers: 1\n");
+ *value = 1;
+ return 0;
+ default:
+ *value = 0;
+ ERROR("query %d unknown!\n", what);
+ return -EINVAL;
+ }
+}
+
+static int cnw_perform(aWindow *base, int op, ...) {
+ CNativeWindow *win = from_base(base);
+ va_list ap;
+ va_start(ap, op);
+
+ switch (op) {
+ case NATIVE_WINDOW_SET_USAGE:
+ TRACE("set usage %d\n", va_arg(ap,int));
+ return 0;
+ case NATIVE_WINDOW_CONNECT:
+ case NATIVE_WINDOW_DISCONNECT:
+ case NATIVE_WINDOW_API_CONNECT:
+ case NATIVE_WINDOW_API_DISCONNECT:
+ return 0;
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ TRACE("set buffers format %d\n", va_arg(ap,int));
+ return 0;
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ TRACE("set buffers transform %d\n", va_arg(ap,int));
+ return 0;
+ case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+ TRACE("set buffers timestamp %lld\n", va_arg(ap,long long));
+ return 0;
+ case NATIVE_WINDOW_SET_SCALING_MODE:
+ TRACE("set scaling mode %d\n", va_arg(ap,int));
+ return 0;
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: {
+ int w = va_arg(ap,int);
+ int h = va_arg(ap,int);
+ if ((w == win->width) && (h == win->height)) {
+ TRACE("set buffers dimensions %d x %d\n", w, h);
+ return 0;
+ }
+ ERROR("cannot resize buffers to %d x %d\n", w, h);
+ return -1;
+ }
+ default:
+ ERROR("perform %d unknown!\n", op);
+ return -ENODEV;
+ }
+}
+
+static void hwc_invalidate(const struct hwc_procs *procs) {}
+static void hwc_vsync(const struct hwc_procs *procs, int disp, int64_t ts) {}
+static void hwc_hotplug(const struct hwc_procs *procs, int disp, int conn) {}
+
+struct hwc_procs hprocs = {
+ .invalidate = hwc_invalidate,
+ .vsync = hwc_vsync,
+ .hotplug = hwc_hotplug,
+};
+
+uint32_t attrs[] = {
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+static int hwc_init(CNativeWindow *win) {
+ hw_module_t const* module;
+ hwc_composer_device_1_t *hwc;
+ unsigned i;
+ int r;
+ uint32_t configs[32];
+ uint32_t numconfigs = 32;
+ int32_t values[8];
+
+ if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
+ ERROR("cannot open hw composer module\n");
+ return -ENODEV;
+ }
+
+ if (hwc_open_1(module, &hwc)) {
+ ERROR("cannot open hwc device\n");
+ return -ENODEV;
+ }
+ win->hwc = hwc;
+
+ LOG("hwc version 0x%08x\n", hwc->common.version);
+
+ if ((hwc->common.version & 0xFFFF0000) < 0x01010000) {
+ ERROR("hwc version less than 1.1\n");
+ hwc_close_1(hwc);
+ return -ENODEV;
+ }
+
+ hwc->registerProcs(hwc, &hprocs);
+
+ if (hwc->getDisplayConfigs(hwc, 0, configs, &numconfigs)) {
+ ERROR("cannot get configs\n");
+ return -ENODEV;
+ }
+ for (i = 0; i < numconfigs; i++)
+ LOG("cfg[%d] = 0x%08x\n", i, configs[i]);
+
+ if ((r = hwc->getDisplayAttributes(hwc, 0, configs[0], attrs, values))) {
+ ERROR("cannot get attributes %d\n", r);
+ return -ENODEV;
+ }
+
+ win->width = values[0];
+ win->height = values[1];
+ win->xdpi = values[3];
+ win->ydpi = values[4];
+ win->format = HAL_PIXEL_FORMAT_RGBA_8888;
+
+ hwc->blank(hwc, 0, 0);
+
+ win->dclist[0] = &(win->dc);
+ return 0;
+}
+
+static aBuffer *cnw_alloc(CNativeWindow *win, unsigned format, unsigned usage) {
+ CNativeBuffer *cnb;
+ aBuffer *buf;
+ int err;
+
+ if (!(cnb = malloc(sizeof(CNativeBuffer))))
+ return 0;
+
+ buf = &cnb->base;
+ cnb->ffd = -1;
+
+ buf->common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+ buf->common.version = sizeof(aBuffer);
+ buf->common.incRef = cnw_inc_ref;
+ buf->common.decRef = cnw_dec_ref;
+
+ buf->width = win->width;
+ buf->height = win->height;
+ buf->format = format;
+ buf->usage = usage;
+
+ err = win->gr->alloc(win->gr, win->width, win->height,
+ format, usage, &buf->handle, &buf->stride);
+ if (err) {
+ ERROR("gralloc of %d x %d failed: err=%d\n",
+ win->width, win->height, err);
+ free(buf);
+ return 0;
+ }
+ INFO("alloc buffer %p %d x %d\n", buf, win->width, win->height);
+ return buf;
+}
+
+static int cnw_init(CNativeWindow *win) {
+ hw_module_t const* module;
+ framebuffer_device_t *fb = NULL;
+ alloc_device_t *gr;
+ int err, i, n;
+ unsigned usage, format;
+
+ memset(win, 0, sizeof(CNativeWindow));
+
+ win->free_buffer_queue.next = &(win->free_buffer_queue);
+ win->free_buffer_queue.prev = &(win->free_buffer_queue);
+
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
+ ERROR("cannot open gralloc module\n");
+ return -ENODEV;
+ }
+
+ if (hwc_init(win)) {
+ ERROR("cannot open hwcomposer, trying legacy fb HAL\n");
+ err = framebuffer_open(module, &fb);
+ if (err) {
+ ERROR("cannot open fb HAL (%s)", strerror(-err));
+ return -ENODEV;
+ }
+ win->width = fb->width;
+ win->height = fb->height;
+ win->format = fb->format;
+ win->xdpi = fb->xdpi;
+ win->ydpi = fb->ydpi;
+ win->fb = fb;
+ }
+
+ INFO("display %d x %d fmt=%d\n",
+ win->width, win->height, win->format);
+
+ err = gralloc_open(module, &gr);
+ if (err) {
+ ERROR("couldn't open gralloc HAL (%s)", strerror(-err));
+ return -ENODEV;
+ }
+ win->gr = gr;
+
+ usage = GRALLOC_USAGE_HW_FB |
+ GRALLOC_USAGE_HW_COMPOSER |
+ GRALLOC_USAGE_HW_RENDER;
+
+ for (i = 0; i < 2; i++) {
+ aBuffer *buf = cnw_alloc(win, win->format, usage);
+ if (!buf)
+ return -ENOMEM;
+ put_back(&win->free_buffer_queue, buf);
+ }
+
+ if (!win->fb && QCT_WORKAROUND) {
+ win->spare = cnw_alloc(win, win->format, usage);
+ if (!win->spare)
+ return -ENOMEM;
+ }
+
+ // Disgusting, but we need to init these "const" fields
+ // and unlike C++ we can't use const_cast<>
+ *((float*) &win->base.xdpi) = win->xdpi;
+ *((float*) &win->base.ydpi) = win->ydpi;
+ *((int*) &win->base.minSwapInterval) = 1;
+ *((int*) &win->base.maxSwapInterval) = 1;
+
+ win->base.common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
+ win->base.common.version = sizeof(aWindow);
+ win->base.common.incRef = cnw_inc_ref;
+ win->base.common.decRef = cnw_dec_ref;
+
+ win->base.setSwapInterval = cnw_set_swap_interval;
+ win->base.dequeueBuffer_DEPRECATED = cnw_dequeue_buffer0;
+ win->base.lockBuffer_DEPRECATED = cnw_lock_buffer0;
+ win->base.queueBuffer_DEPRECATED = cnw_queue_buffer0;
+ win->base.query = cnw_query;
+ win->base.perform = cnw_perform;
+ win->base.cancelBuffer_DEPRECATED = cnw_cancel_buffer0;
+ win->base.dequeueBuffer = cnw_dequeue_buffer1;
+ win->base.queueBuffer = cnw_queue_buffer1;
+ win->base.cancelBuffer = cnw_cancel_buffer1;
+
+ pthread_mutex_init(&win->lock, NULL);
+ pthread_cond_init(&win->cvar, NULL);
+
+ return 0;
+}
+
+void cnw_destroy(CNativeWindow *win) {
+ if (win->fb)
+ framebuffer_close(win->fb);
+ if (win->hwc)
+ hwc_close_1(win->hwc);
+ if (win->gr)
+ gralloc_close(win->gr);
+ free(win);
+}
+
+CNativeWindow *cnw_create(void) {
+ CNativeWindow *win;
+ char *x;
+ if ((x = getenv("CNWDEBUG")))
+ trace_level = atoi(x);
+ if (!(win = malloc(sizeof(CNativeWindow))))
+ return NULL;
+ if (cnw_init(win)) {
+ cnw_destroy(win);
+ return NULL;
+ }
+ return win;
+}
+
+void cnw_info(CNativeWindow *win, unsigned *w, unsigned *h, unsigned *fmt) {
+ *w = win->width;
+ *h = win->height;
+ *fmt = win->format;
+}
+
diff --git a/tests/hwc/test-arrows.c b/tests/hwc/test-arrows.c
new file mode 100644
index 00000000..a35faa7b
--- /dev/null
+++ b/tests/hwc/test-arrows.c
@@ -0,0 +1,164 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+
+#include "util.h"
+
+static const char gVertexShader[] =
+ "attribute vec4 aPosition;\n"
+ "uniform mat4 uTransform;\n"
+ "varying vec4 vTexCoord;\n"
+ "void main() {\n"
+ " gl_Position = aPosition * uTransform;\n"
+ " vTexCoord = aPosition * vec4(1.0/16.0,-1.0/16.0,0.0,0.0);\n"
+ "}\n";
+
+static const char gFragmentShader[] =
+ "precision mediump float;\n"
+ "uniform sampler2D uTexture;\n"
+ "uniform float uAnim;\n"
+ "varying vec4 vTexCoord;\n"
+ "void main() {\n"
+ " vec2 tc = vec2(vTexCoord.x, uAnim + vTexCoord.y);\n"
+ " gl_FragColor = texture2D(uTexture, tc);\n"
+ "}\n";
+
+static GLuint pgm;
+static GLint aPosition, uTransform, uTexture, uAnim;
+
+static GLfloat vtx[2 * 3 * 2];
+static GLfloat mtx[16];
+
+//#define R (0xFF0000FF)
+#define R (0xFF000000)
+#define G (0xFF00FF00)
+uint32_t t32[] = {
+ R, R, R, R, R, R, R, G, G, R, R, R, R, R, R, R,
+ R, R, R, R, R, R, G, G, G, G, R, R, R, R, R, R,
+ R, R, R, R, R, G, G, G, G, G, G, R, R, R, R, R,
+ R, R, R, R, G, G, G, G, G, G, G, G, R, R, R, R,
+ R, R, R, G, G, G, G, G, G, G, G, G, G, R, R, R,
+ R, R, G, G, G, G, G, G, G, G, G, G, G, G, R, R,
+ R, R, G, G, G, G, G, G, G, G, G, G, G, G, R, R,
+ R, R, R, R, R, R, G, G, G, G, R, R, R, R, R, R,
+ R, R, R, R, R, R, G, G, G, G, R, R, R, R, R, R,
+ R, R, R, R, R, R, G, G, G, G, R, R, R, R, R, R,
+ R, R, R, R, R, R, G, G, G, G, R, R, R, R, R, R,
+ R, R, R, R, R, R, G, G, G, G, R, R, R, R, R, R,
+ R, R, R, R, R, R, G, G, G, G, R, R, R, R, R, R,
+ R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R,
+ R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R,
+ R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R,
+};
+#undef R
+#undef G
+
+int prepare(int w, int h) {
+ GLuint texid;
+
+ int left = w / 4;
+ int top = h / 4;
+ int right = (w / 4) * 3;
+ int bottom = (h / 4) * 3;
+
+ vtx[0] = left;
+ vtx[1] = top;
+ vtx[2] = left;
+ vtx[3] = bottom;
+ vtx[4] = right;
+ vtx[5] = bottom;
+
+ vtx[6] = right;
+ vtx[7] = bottom;
+ vtx[8] = right;
+ vtx[9] = top;
+ vtx[10] = left;
+ vtx[11] = top;
+
+ matrix_init_ortho(mtx, w, h);
+
+ pgm = load_program(gVertexShader, gFragmentShader);
+ if (!pgm)
+ return -1;
+
+ aPosition = glGetAttribLocation(pgm, "aPosition");
+ uTexture = glGetUniformLocation(pgm, "uTexture");
+ uTransform = glGetUniformLocation(pgm, "uTransform");
+ uAnim = glGetUniformLocation(pgm, "uAnim");
+
+ glViewport(0, 0, w, h);
+
+ glGenTextures(1, &texid);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texid);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glEnable(GL_TEXTURE_2D);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, t32);
+
+ return 0;
+}
+
+static float anim = 0.0;
+
+void render() {
+ anim += 0.1;
+ if (anim >= 16.0) anim = 0.0;
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ glUseProgram(pgm);
+ glUniform1i(uTexture, 0);
+ glUniform1f(uAnim, anim);
+ glUniformMatrix4fv(uTransform, 1, 0, mtx);
+ glVertexAttribPointer(aPosition, 2, GL_FLOAT, GL_FALSE, 0, vtx);
+ glEnableVertexAttribArray(aPosition);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
+int main(int argc, char **argv) {
+ EGLDisplay display;
+ EGLSurface surface;
+ int w, h, count;
+
+ if (argc > 1)
+ count = atoi(argv[1]);
+
+ if (egl_create(&display, &surface, &w, &h))
+ return -1;
+
+ if (prepare(w, h))
+ return -1;
+
+ for (;;) {
+ render();
+ eglSwapBuffers(display, surface);
+ if (count > 0)
+ if (--count == 0)
+ break;
+ }
+
+ egl_destroy(display, surface);
+ return 0;
+}
diff --git a/tests/hwc/util.c b/tests/hwc/util.c
new file mode 100644
index 00000000..89313054
--- /dev/null
+++ b/tests/hwc/util.c
@@ -0,0 +1,236 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+
+#include <system/graphics.h>
+
+#include "util.h"
+
+void matrix_init_ortho(GLfloat *m, float w, float h) {
+ m[0] = 2.0 / w;
+ m[1] = 0.0;
+ m[2] = 0.0;
+ m[3] = -1.0;
+ m[4] = 0.0;
+ m[5] = 2.0 / h;
+ m[6] = 0.0;
+ m[7] = -1.0;
+ m[8] = 0.0;
+ m[9] = 0.0;
+ m[10] -1.0;
+ m[11] = 0.0;
+ m[12] = 0.0;
+ m[13] = 0.0;
+ m[14] = 0.0;
+ m[15] = 1.0;
+}
+
+static GLuint load_shader(GLenum shaderType, const char *src) {
+ GLint status = 0, len = 0;
+ GLuint shader;
+
+ if (!(shader = glCreateShader(shaderType)))
+ return 0;
+
+ glShaderSource(shader, 1, &src, NULL);
+ glCompileShader(shader);
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+
+ if (status)
+ return shader;
+
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
+ if (len) {
+ char *msg = malloc(len);
+ if (msg) {
+ glGetShaderInfoLog(shader, len, NULL, msg);
+ msg[len-1] = 0;
+ fprintf(stderr, "error compiling shader:\n%s\n", msg);
+ free(msg);
+ }
+ }
+ glDeleteShader(shader);
+ return 0;
+}
+
+GLuint load_program(const char *vert_src, const char *frag_src) {
+ GLuint vert, frag, prog;
+ GLint status = 0, len = 0;
+
+ if (!(vert = load_shader(GL_VERTEX_SHADER, vert_src)))
+ return 0;
+ if (!(frag = load_shader(GL_FRAGMENT_SHADER, frag_src)))
+ goto fail_frag;
+ if (!(prog = glCreateProgram()))
+ goto fail_prog;
+
+ glAttachShader(prog, vert);
+ glAttachShader(prog, frag);
+ glLinkProgram(prog);
+
+ glGetProgramiv(prog, GL_LINK_STATUS, &status);
+ if (status)
+ return prog;
+
+ glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
+ if (len) {
+ char *buf = (char*) malloc(len);
+ if (buf) {
+ glGetProgramInfoLog(prog, len, NULL, buf);
+ buf[len-1] = 0;
+ fprintf(stderr, "error linking program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(prog);
+fail_prog:
+ glDeleteShader(frag);
+fail_frag:
+ glDeleteShader(vert);
+ return 0;
+}
+
+int select_config_for_window(EGLDisplay dpy, EGLint *attr,
+ unsigned format, EGLConfig *config) {
+ EGLint R,G,B,A,r,g,b,a;
+ EGLint i, n, max;
+ EGLConfig *cfg;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ R = G = B = A = 8;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ R = 5; G = 6; B = 5; A = 0;
+ break;
+ default:
+ fprintf(stderr, "unknown fb pixel format %d\n", format);
+ return -1;
+ }
+
+ if (eglGetConfigs(dpy, NULL, 0, &max) == EGL_FALSE) {
+ fprintf(stderr, "no EGL configurations available?!\n");
+ return -1;
+ }
+
+ cfg = (EGLConfig*) malloc(sizeof(EGLConfig) * max);
+ if (!cfg)
+ return -1;
+
+ if (eglChooseConfig(dpy, attr, cfg, max, &n) == EGL_FALSE) {
+ fprintf(stderr, "eglChooseConfig failed\n");
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(dpy, cfg[i], EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, cfg[i], EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, cfg[i], EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, cfg[i], EGL_ALPHA_SIZE, &a);
+ if (r == R && g == G && b == B && a == A) {
+ *config = cfg[i];
+ free(cfg);
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "cannot find matching config\n");
+ free(cfg);
+ return -1;
+}
+
+static struct CNativeWindow *_cnw = 0;
+
+int egl_create(EGLDisplay *_display, EGLSurface *_surface, int *_w, int *_h) {
+ EGLBoolean res;
+ EGLConfig config = { 0 };
+ EGLint context_attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint config_attrs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+ EGLint major, minor;
+ EGLContext context;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay display;
+ EGLNativeWindowType window;
+ unsigned width, height, format;
+ struct CNativeWindow *cnw;
+
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (display == EGL_NO_DISPLAY)
+ return -1;
+
+ if (!(res = eglInitialize(display, &major, &minor)))
+ return -1;
+
+ fprintf(stderr, "egl version: %d.%d\n", major, minor);
+
+ if ((cnw = cnw_create()) == 0)
+ return -1;
+
+ cnw_info(cnw, &width, &height, &format);
+ window = (EGLNativeWindowType) cnw;
+
+ if ((res = select_config_for_window(display, config_attrs, format, &config)))
+ goto fail;
+
+ surface = eglCreateWindowSurface(display, config, window, NULL);
+ if (surface == EGL_NO_SURFACE)
+ goto fail;
+
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attrs);
+ if (context == EGL_NO_CONTEXT)
+ goto fail;
+
+ if (!(res = eglMakeCurrent(display, surface, surface, context)))
+ goto fail;
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &w);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+
+ fprintf(stderr, "window: %d x %d\n", w, h);
+
+ *_display = display;
+ *_surface = surface;
+ *_w = w;
+ *_h = h;
+
+ _cnw = cnw;
+ return 0;
+
+fail:
+ cnw_destroy(cnw);
+ return -1;
+}
+
+void egl_destroy(EGLDisplay display, EGLSurface surface) {
+ if (_cnw) {
+ eglDestroySurface(display, surface);
+ eglTerminate(display);
+ cnw_destroy(_cnw);
+ _cnw = 0;
+ }
+}
diff --git a/tests/hwc/util.h b/tests/hwc/util.h
new file mode 100644
index 00000000..a0d38ce0
--- /dev/null
+++ b/tests/hwc/util.h
@@ -0,0 +1,38 @@
+/*
+ * 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 _GL_UTIL_H_
+#define _GL_UTIL_H_
+
+/* convenience */
+
+GLuint load_program(const char *vert_src, const char *frag_src);
+void matrix_init_ortho(GLfloat *m, float w, float h);
+
+/* context setup / teardown */
+
+int egl_create(EGLDisplay *_display, EGLSurface *_surface, int *_w, int *_h);
+void egl_destroy(EGLDisplay display, EGLSurface surface);
+
+/* internals needed by util.c */
+
+struct CNativeWindow;
+struct CNativeWindow *cnw_create(void);
+void cnw_destroy(struct CNativeWindow *win);
+void cnw_info(struct CNativeWindow *win,
+ unsigned *w, unsigned *h, unsigned *fmt);
+
+#endif