Merge "Add header for new NVRAM HAL." am: 6b09c49633
am: 330ee96ad9
* commit '330ee96ad9ca40f38525dc575b7d4dbe337e7184':
Add header for new NVRAM HAL.
diff --git a/hardware.c b/hardware.c
index 79d0a2f..5394787 100644
--- a/hardware.c
+++ b/hardware.c
@@ -31,9 +31,11 @@
#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
+#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
+#define HAL_LIBRARY_PATH3 "/odm/lib/hw"
#endif
/**
@@ -130,6 +132,11 @@
const char *subname)
{
snprintf(path, path_len, "%s/%s.%s.so",
+ HAL_LIBRARY_PATH3, name, subname);
+ if (access(path, R_OK) == 0)
+ return 0;
+
+ snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, subname);
if (access(path, R_OK) == 0)
return 0;
diff --git a/include/hardware/activity_recognition.h b/include/hardware/activity_recognition.h
index 8f99459..2200723 100644
--- a/include/hardware/activity_recognition.h
+++ b/include/hardware/activity_recognition.h
@@ -179,9 +179,27 @@
* independently of the other. The HAL implementation needs to keep track of which pairs are
* currently active and needs to detect only those pairs.
*
+ * At the first detection after this function gets called, the hardware should know whether the
+ * user is in the activity.
+ * - If event_type is ACTIVITY_EVENT_ENTER and the user is in the activity, then an
+ * (ACTIVITY_EVENT_ENTER, activity) event should be added to the FIFO.
+ * - If event_type is ACTIVITY_EVENT_EXIT and the user is not in the activity, then an
+ * (ACTIVITY_EVENT_EXIT, activity) event should be added to the FIFO.
+ * For example, suppose get_supported_activities_list contains on_bicyle and running, and the
+ * user is biking. Consider the following four calls that could happen in any order.
+ * - When enable_activity_event(on_bicycle, ACTIVITY_EVENT_ENTER) is called,
+ * (ACTIVITY_EVENT_ENTER, on_bicycle) should be added to the FIFO.
+ * - When enable_activity_event(on_bicycle, ACTIVITY_EVENT_EXIT) is called, nothing should be
+ * added to the FIFO.
+ * - When enable_activity_event(running, ACTIVITY_EVENT_ENTER) is called, nothing should be
+ * added to the FIFO.
+ * - When enable_activity_event(running, ACTIVITY_EVENT_EXIT) is called,
+ * (ACTIVITY_EVENT_EXIT, running) should be added to the FIFO.
+ *
* activity_handle - Index of the specific activity that needs to be detected in the list
* returned by get_supported_activities_list.
- * event_type - Specific transition of the activity that needs to be detected.
+ * event_type - Specific transition of the activity that needs to be detected. It should be
+ * either ACTIVITY_EVENT_ENTER or ACTIVITY_EVENT_EXIT.
* max_batch_report_latency_ns - a transition can be delayed by at most
* “max_batch_report_latency” nanoseconds.
* Return 0 on success, negative errno code otherwise.
@@ -190,7 +208,8 @@
uint32_t activity_handle, uint32_t event_type, int64_t max_batch_report_latency_ns);
/*
- * Disables detection of a specific (activity, event_type) pair.
+ * Disables detection of a specific (activity, event_type) pair. All the (activity, event_type)
+ * events in the FIFO are discarded.
*/
int (*disable_activity_event)(const struct activity_recognition_device* dev,
uint32_t activity_handle, uint32_t event_type);
@@ -199,6 +218,7 @@
* Flush all the batch FIFOs. Report all the activities that were stored in the FIFO so far as
* if max_batch_report_latency had expired. This shouldn't change the latency in any way. Add
* a flush_complete_event to indicate the end of the FIFO after all events are delivered.
+ * activity_callback should be called before this function returns successfully.
* See ACTIVITY_EVENT_FLUSH_COMPLETE for more details.
* Return 0 on success, negative errno code otherwise.
*/
diff --git a/include/hardware/audio.h b/include/hardware/audio.h
index 2389c09..29b695c 100644
--- a/include/hardware/audio.h
+++ b/include/hardware/audio.h
@@ -144,6 +144,9 @@
/* Set the HW synchronization source for an output stream. */
#define AUDIO_PARAMETER_STREAM_HW_AV_SYNC "hw_av_sync"
+/* Enable mono audio playback if 1, else should be 0. */
+#define AUDIO_PARAMETER_MONO_OUTPUT "mono_output"
+
/**
* audio codec parameters
*/
diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h
index d920d4b..2b7add0 100644
--- a/include/hardware/camera2.h
+++ b/include/hardware/camera2.h
@@ -23,7 +23,10 @@
/**
* Camera device HAL 2.1 [ CAMERA_DEVICE_API_VERSION_2_0, CAMERA_DEVICE_API_VERSION_2_1 ]
*
- * DEPRECATED. New devices should use Camera HAL v3.2 or newer.
+ * NO LONGER SUPPORTED. The camera service will no longer load HAL modules that
+ * contain HAL v2.0 or v2.1 devices.
+ *
+ * New devices should use Camera HAL v3.2 or newer.
*
* Supports the android.hardware.Camera API, and the android.hardware.camera2
* API in legacy mode only.
diff --git a/include/hardware/camera_common.h b/include/hardware/camera_common.h
index 7658dd4..c74d7bb 100644
--- a/include/hardware/camera_common.h
+++ b/include/hardware/camera_common.h
@@ -140,17 +140,18 @@
* All device versions <= HARDWARE_DEVICE_API_VERSION(1, 0xFF) must be treated
* as CAMERA_DEVICE_API_VERSION_1_0
*/
-#define CAMERA_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0)
-#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_1_0 HARDWARE_DEVICE_API_VERSION(1, 0) // DEPRECATED
+#define CAMERA_DEVICE_API_VERSION_2_0 HARDWARE_DEVICE_API_VERSION(2, 0) // NO LONGER SUPPORTED
+#define CAMERA_DEVICE_API_VERSION_2_1 HARDWARE_DEVICE_API_VERSION(2, 1) // NO LONGER SUPPORTED
#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)
#define CAMERA_DEVICE_API_VERSION_3_2 HARDWARE_DEVICE_API_VERSION(3, 2)
#define CAMERA_DEVICE_API_VERSION_3_3 HARDWARE_DEVICE_API_VERSION(3, 3)
+#define CAMERA_DEVICE_API_VERSION_3_4 HARDWARE_DEVICE_API_VERSION(3, 4)
-// Device version 3.3 is current, older HAL camera device versions are not
+// Device version 3.4 is current, older HAL camera device versions are not
// recommended for new devices.
-#define CAMERA_DEVICE_API_VERSION_CURRENT CAMERA_DEVICE_API_VERSION_3_3
+#define CAMERA_DEVICE_API_VERSION_CURRENT CAMERA_DEVICE_API_VERSION_3_4
/**
* Defined in /system/media/camera/include/system/camera_metadata.h
diff --git a/include/hardware/context_hub.h b/include/hardware/context_hub.h
new file mode 100644
index 0000000..01d2377
--- /dev/null
+++ b/include/hardware/context_hub.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2016 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 CONTEXT_HUB_H
+#define CONTEXT_HUB_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <hardware/hardware.h>
+
+/**
+ * This header file defines the interface of a Context Hub Implementation to
+ * the Android service exposing Context hub capabilities to applications.
+ * The Context hub is expected to a low power compute domain with the following
+ * defining charecteristics -
+ *
+ * 1) Access to sensors like accelerometer, gyroscope, magenetometer.
+ * 2) Access to radios like GPS, Wifi, Bluetooth etc.
+ * 3) Access to low power audio sensing.
+ *
+ * Implementations of this HAL can add additional sensors not defined by the
+ * Android API. Such information sources shall be private to the implementation.
+ *
+ * The Context Hub HAL exposes the construct of code download. A piece of binary
+ * code can be pushed to the context hub through the supported APIs.
+ *
+ * This version of the HAL designs in the possibility of multiple context hubs.
+ */
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define CONTEXT_HUB_HEADER_VERSION 1
+#define CONTEXT_HUB_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION_2(1, 0, CONTEXT_HUB_HEADER_VERSION)
+
+/**
+ * The id of this module
+ */
+#define CONTEXT_HUB_MODULE_ID "context_hub"
+
+/**
+ * Name of the device to open
+ */
+#define CONTEXT_HUB_HARDWARE_POLL "ctxt_poll"
+
+/**
+ * Memory types for code upload. Device-specific. At least HUB_MEM_TYPE_MAIN must be supported
+ */
+#define HUB_MEM_TYPE_MAIN 0
+#define HUB_MEM_TYPE_SECONDARY 1
+#define HUB_MEM_TYPE_TCM 2
+
+
+#define HUB_MEM_TYPE_FIRST_VENDOR 0x80000000ul
+
+
+/**
+ * Other memory types (likely not writeable, informational only)
+ */
+#define HUB_MEM_TYPE_BOOTLOADER 0xfffffffful
+#define HUB_MEM_TYPE_OS 0xfffffffeul
+#define HUB_MEM_TYPE_EEDATA 0xfffffffdul
+#define HUB_MEM_TYPE_RAM 0xfffffffcul
+
+/**
+ * Types of memory blocks on the context hub
+ * */
+#define MEM_FLAG_READ 0x1 // Memory can be written to
+#define MEM_FLAG_WRITE 0x2 // Memory can be written to
+#define MEM_FLAG_EXEC 0x4 // Memory can be executed from
+
+/**
+ * The following structure defines each memory block in detail
+ */
+struct mem_range_t {
+ uint32_t total_bytes;
+ uint32_t free_bytes;
+ uint32_t type; // HUB_MEM_TYPE_*
+ uint32_t mem_flags; // MEM_FLAG_*
+};
+
+
+/**
+ * App names may be strings, bytes, uints, etc. This caovers all types of app names
+ */
+struct hub_app_name_t {
+ uint32_t app_name_len;
+ const void *app_name;
+};
+
+struct hub_app_info {
+ const struct hub_app_name_t *name;
+ uint32_t version;
+ uint32_t num_mem_ranges;
+ const struct mem_range_t *mem_usage;
+};
+
+/**
+ * Following enum defines the types of sensors that a hub may declare support
+ * for. Declaration for support would mean that the hub can access and process
+ * data from that particular sensor type.
+ */
+
+typedef enum {
+ CONTEXT_SENSOR_RESERVED, // 0
+ CONTEXT_SENSOR_ACCELEROMETER, // 1
+ CONTEXT_SENSOR_GYROSCOPE, // 2
+ CONTEXT_SENSOR_MAGNETOMETER, // 3
+ CONTEXT_SENSOR_BAROMETER, // 4
+ CONTEXT_SENSOR_PROXIMITY_SENSOR, // 5
+ CONTEXT_SENSOR_AMBIENT_LIGHT_SENSOR, // 6
+
+ CONTEXT_SENSOR_GPS = 0x100, // 0x100
+ // Reserving this space for variants on GPS
+ CONTEXT_SENSOR_WIFI = 0x200, // 0x200
+ // Reserving this space for variants on WIFI
+ CONTEXT_SENSOR_AUDIO = 0x300, // 0x300
+ // Reserving this space for variants on Audio
+ CONTEXT_SENSOR_CAMERA = 0x400, // 0x400
+ // Reserving this space for variants on Camera
+ CONTEXT_SENSOR_BLE = 0x500, // 0x500
+
+ CONTEXT_SENSOR_MAX = 0xffffffff, //make sure enum size is set
+} context_sensor_e;
+
+/**
+ * Sensor types beyond CONTEXT_HUB_TYPE_PRIVATE_SENSOR_BASE are custom types
+ */
+#define CONTEXT_HUB_TYPE_PRIVATE_SENSOR_BASE 0x10000
+
+/**
+ * The following structure describes a sensor
+ */
+struct physical_sensor_description_t {
+ uint32_t sensor_type; // From the definitions above eg: 100
+ const char *type_string; // Type as a string. eg: "GPS"
+ const char *name; // Identifier eg: "Bosch BMI160"
+ const char *vendor; // Vendor : eg "STM"
+ uint32_t version; // Version : eg 0x1001
+ uint32_t fifo_reserverd_count; // Batching possible in hardware. Please
+ // note that here hardware does not include
+ // the context hub itslef. Thus, this
+ // definition may be different from say the
+ // number advertised in the sensors HAL
+ // which allows for batching in a hub.
+ uint32_t fifo_max_count; // maximum number of batchable events.
+ uint64_t min_delay_ms; // in milliseconds, corresponding to highest
+ // sampling freq.
+ uint64_t max_delay_ms; // in milliseconds, corresponds to minimum
+ // sampling frequency
+ float peak_power_mw; // At max frequency & no batching, power
+ // in milliwatts
+};
+
+struct connected_sensor_t {
+ uint32_t sensor_id; // identifier for this sensor
+
+ /* This union may be extended to other sensor types */
+ union {
+ struct physical_sensor_description_t physical_sensor;
+ };
+};
+
+
+
+/**
+ * Messages of this length or less must be supported by all implementations,
+ * longer lengths are supported up to max_supported_msg_len. This is exposed
+ * to third party apps, and since we do not know their msg data formats we
+ * cannot fragment for them. Our own messages are allowed to be bigger and
+ * this HAL will fragment as needed. "Our own" messages are messaegs defined
+ * in this file.
+ */
+#define HUB_REQUIRED_SUPPORTED_MSG_LEN 128
+
+struct hub_message_t {
+ const struct hub_app_name_t *app; /* To/From this nanoapp */
+ uint32_t message_type;
+ uint32_t message_len;
+ const void *message;
+};
+
+
+/**
+ * Definition of a context hub. A device may contain more than one low
+ * power domain. In that case, please add an entry for each hub. However,
+ * it is perfectly OK for a device to declare one context hub and manage
+ * them internally as several
+ */
+
+struct context_hub_t {
+ const char *name; // descriptive name eg: "Awesome Hub #1"
+ const char *vendor; // hub hardware vendor eg: "Qualcomm"
+ const char *toolchain; // toolchain to make binaries eg:"gcc ARM"
+ uint32_t platform_version; // Version of the hardware : eg 0x20
+ uint32_t toolchain_version; // Version of the toolchain : eg: 0x484
+ uint32_t hub_id; // a device unique id for this hub
+
+ float peak_mips; // Peak MIPS platform can deliver
+ float stopped_power_draw_mw; // if stopped, retention power, milliwatts
+ float sleep_power_draw_mw; // if sleeping, retention power, milliwatts
+ float peak_power_draw_mw; // for a busy CPUm power in milliwatts
+
+ const struct connected_sensor_t *connected_sensors; // array of connected sensors
+ uint32_t num_connected_sensors; // number of connected sensors
+
+ uint32_t max_supported_msg_len;
+ const struct hub_app_name_t *os_app_name; /* send msgs here for OS functions */
+};
+
+/**
+ * All communication between the context hubs and the Context Hub Service is in
+ * the form of messages. Some message types are distinguished and their
+ * Semantics shall be well defined.
+ * Custom message types should be defined starting above
+ * CONTEXT_HUB_PRIVATE_MSG_BASE
+ */
+
+typedef enum {
+ CONTEXT_HUB_APPS_ENABLE = 1, // 1: Enables the loaded nano-apps
+ CONTEXT_HUB_APPS_DISABLE, // 2: Disables any loaded nano-apps
+ CONTEXT_HUB_LOAD_APP, // 3: Load a supplied app
+ CONTEXT_HUB_UNLOAD_APP, // 4: Unload a specified app
+ CONTEXT_HUB_QUERY_APPS, // 5: Query for apps info on hub (gets struct hub_app_info[])
+ CONTEXT_HUB_QUERY_MEMORY, // 5: Query for memory info (gets struct mem_range_t[])
+ CONTEXT_HUB_LOAD_OS, // 6: Load up OS update
+} hub_messages_e;
+
+#define CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE 0x10000
+
+
+/**
+ * A callback registers with the context hub service to pass messages
+ * coming from the hub to the service/clients.
+ */
+typedef int context_hub_callback(uint32_t hub_id, const struct hub_message_t *rxed_msg, void *cookie);
+
+
+/**
+ * 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.
+ */
+struct context_hub_module_t {
+ struct hw_module_t common;
+
+ /**
+ * Enumerate all available hubs.The list is returned in "list".
+ * @return result : 0 if successful, error code otherwise
+ *
+ * This method shall be called at device bootup.
+ */
+ int (*get_hubs)(struct context_hub_module_t* module, const struct context_hub_t ** list);
+
+ /**
+ * Registers a callback for the HAL implementation to communicate
+ * with the context hub service.
+ * @return result : 0 if successful, error code otherwise
+ */
+ int (*subscribe_messages)(uint32_t hub_id, context_hub_callback cbk, void *cookie);
+
+ /**
+ * Send a message to a hub
+ * @return result : 0 if successful, error code otherwise
+ */
+ int (*send_message)(uint32_t hub_id, const struct hub_message_t *msg);
+
+};
+
+__END_DECLS
+
+#endif // CONTEXT_HUB_SENSORS_INTERFACE_H
diff --git a/include/hardware/fingerprint.h b/include/hardware/fingerprint.h
index ac88c10..b567732 100644
--- a/include/hardware/fingerprint.h
+++ b/include/hardware/fingerprint.h
@@ -21,6 +21,7 @@
#define FINGERPRINT_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
#define FINGERPRINT_MODULE_API_VERSION_2_0 HARDWARE_MODULE_API_VERSION(2, 0)
+#define FINGERPRINT_MODULE_API_VERSION_2_1 HARDWARE_MODULE_API_VERSION(2, 1)
#define FINGERPRINT_HARDWARE_MODULE_ID "fingerprint"
typedef enum fingerprint_msg_type {
@@ -28,7 +29,8 @@
FINGERPRINT_ACQUIRED = 1,
FINGERPRINT_TEMPLATE_ENROLLING = 3,
FINGERPRINT_TEMPLATE_REMOVED = 4,
- FINGERPRINT_AUTHENTICATED = 5
+ FINGERPRINT_AUTHENTICATED = 5,
+ FINGERPRINT_TEMPLATE_ENUMERATING = 6,
} fingerprint_msg_type_t;
/*
@@ -48,6 +50,7 @@
FINGERPRINT_ERROR_NO_SPACE = 4, /* No space available to store a template */
FINGERPRINT_ERROR_CANCELED = 5, /* The current operation can't proceed. See above. */
FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6, /* fingerprint with given id can't be removed */
+ FINGERPRINT_ERROR_LOCKOUT = 7, /* the functionality is temporarily locked out */
FINGERPRINT_ERROR_VENDOR_BASE = 1000 /* vendor-specific error messages start here */
} fingerprint_error_t;
@@ -82,6 +85,11 @@
uint64_t msg; /* Vendor specific message. Used for user guidance */
} fingerprint_enroll_t;
+typedef struct fingerprint_enumerated {
+ fingerprint_finger_id_t finger;
+ uint32_t remaining_templates;
+} fingerprint_enumerated_t;
+
typedef struct fingerprint_removed {
fingerprint_finger_id_t finger;
} fingerprint_removed_t;
@@ -100,6 +108,7 @@
union {
fingerprint_error_t error;
fingerprint_enroll_t enroll;
+ fingerprint_enumerated_t enumerated;
fingerprint_removed_t removed;
fingerprint_acquired_t acquired;
fingerprint_authenticated_t authenticated;
@@ -198,31 +207,24 @@
/*
* Enumerate all the fingerprint templates found in the directory set by
* set_active_group()
- * This is a synchronous call. The function takes:
- * - A pointer to an array of fingerprint_finger_id_t.
- * - The size of the array provided, in fingerprint_finger_id_t elements.
- * Max_size is a bi-directional parameter and returns the actual number
- * of elements copied to the caller supplied array.
- * In the absence of errors the function returns the total number of templates
- * in the user directory.
- * If the caller has no good guess on the size of the array he should call this
- * function witn *max_size == 0 and use the return value for the array allocation.
- * The caller of this function has a complete list of the templates when *max_size
- * is the same as the function return.
+ * For each template found notify() will be called with:
+ * fingerprint_msg.type == FINGERPRINT_TEMPLATE_ENUMERATED
+ * fingerprint_msg.data.enumerated.finger indicating a template id
+ * fingerprint_msg.data.enumerated.remaining_templates indicating how many more
+ * enumeration messages to expect.
*
- * Function return: Total number of fingerprint templates in the current storage directory.
+ * Function return: 0 if enumerate request is accepted
* or a negative number in case of error, generally from the errno.h set.
*/
- int (*enumerate)(struct fingerprint_device *dev, fingerprint_finger_id_t *results,
- uint32_t *max_size);
+ int (*enumerate)(struct fingerprint_device *dev);
/*
* Fingerprint remove request:
* Deletes a fingerprint template.
- * Works only within a path set by set_active_group().
+ * Works only within the path set by set_active_group().
* notify() will be called with details on the template deleted.
* fingerprint_msg.type == FINGERPRINT_TEMPLATE_REMOVED and
- * fingerprint_msg.data.removed.id indicating the template id removed.
+ * fingerprint_msg.data.removed.finger indicating the template id removed.
*
* Function return: 0 if fingerprint template(s) can be successfully deleted
* or a negative number in case of error, generally from the errno.h set.
@@ -249,8 +251,16 @@
*/
int (*authenticate)(struct fingerprint_device *dev, uint64_t operation_id, uint32_t gid);
+ /*
+ * Resets a lockout by providing a valid hardware authentication token.
+ *
+ * Function return: 0 on success
+ * or a negative number in case of error, generally from the errno.h set.
+ */
+ int (*reset_lockout)(struct fingerprint_device *dev, const hw_auth_token_t *hat);
+
/* Reserved for backward binary compatibility */
- void *reserved[4];
+ void *reserved[3];
} fingerprint_device_t;
typedef struct fingerprint_module {
diff --git a/include/hardware/gps.h b/include/hardware/gps.h
index 76b6cb7..6fd47a9 100644
--- a/include/hardware/gps.h
+++ b/include/hardware/gps.h
@@ -53,7 +53,7 @@
#define GPS_POSITION_MODE_MS_BASED 1
/**
* AGPS MS-Assisted mode. This mode is not maintained by the platform anymore.
- * It is strongly recommended to use GPS_POSITION_MODE_MS_BASE instead.
+ * It is strongly recommended to use GPS_POSITION_MODE_MS_BASED instead.
*/
#define GPS_POSITION_MODE_MS_ASSISTED 2
@@ -98,28 +98,31 @@
/** Flags for the gps_set_capabilities callback. */
-/** GPS HAL schedules fixes for GPS_POSITION_RECURRENCE_PERIODIC mode.
- If this is not set, then the framework will use 1000ms for min_interval
- and will start and call start() and stop() to schedule the GPS.
+/**
+ * GPS HAL schedules fixes for GPS_POSITION_RECURRENCE_PERIODIC mode. If this is
+ * not set, then the framework will use 1000ms for min_interval and will start
+ * and call start() and stop() to schedule the GPS.
*/
-#define GPS_CAPABILITY_SCHEDULING 0x0000001
+#define GPS_CAPABILITY_SCHEDULING (1 << 0)
/** GPS supports MS-Based AGPS mode */
-#define GPS_CAPABILITY_MSB 0x0000002
+#define GPS_CAPABILITY_MSB (1 << 1)
/** GPS supports MS-Assisted AGPS mode */
-#define GPS_CAPABILITY_MSA 0x0000004
+#define GPS_CAPABILITY_MSA (1 << 2)
/** GPS supports single-shot fixes */
-#define GPS_CAPABILITY_SINGLE_SHOT 0x0000008
+#define GPS_CAPABILITY_SINGLE_SHOT (1 << 3)
/** GPS supports on demand time injection */
-#define GPS_CAPABILITY_ON_DEMAND_TIME 0x0000010
+#define GPS_CAPABILITY_ON_DEMAND_TIME (1 << 4)
/** GPS supports Geofencing */
-#define GPS_CAPABILITY_GEOFENCING 0x0000020
+#define GPS_CAPABILITY_GEOFENCING (1 << 5)
/** GPS supports Measurements */
-#define GPS_CAPABILITY_MEASUREMENTS 0x0000040
+#define GPS_CAPABILITY_MEASUREMENTS (1 << 6)
/** GPS supports Navigation Messages */
-#define GPS_CAPABILITY_NAV_MESSAGES 0x0000080
+#define GPS_CAPABILITY_NAV_MESSAGES (1 << 7)
-/** Flags used to specify which aiding data to delete
- when calling delete_aiding_data(). */
+/**
+ * Flags used to specify which aiding data to delete when calling
+ * delete_aiding_data().
+ */
typedef uint16_t GpsAidingData;
// IMPORTANT: Note that the following values must match
// constants in GpsLocationProvider.java.
@@ -210,9 +213,11 @@
/** AGPS data connection failed */
#define GPS_AGPS_DATA_CONN_FAILED 5
+typedef uint16_t AGpsRefLocationType;
#define AGPS_REF_LOCATION_TYPE_GSM_CELLID 1
#define AGPS_REF_LOCATION_TYPE_UMTS_CELLID 2
#define AGPS_REG_LOCATION_TYPE_MAC 3
+#define AGPS_REF_LOCATION_TYPE_LTE_CELLID 4
/** Network types for update_network_state "type" parameter */
#define AGPS_RIL_NETWORK_TYPE_MOBILE 0
@@ -246,9 +251,14 @@
* Enumeration of the available values for the GPS Clock type.
*/
typedef uint8_t GpsClockType;
-/** The type is not available ot it is unknown. */
+/** The type is not available or it is unknown. */
#define GPS_CLOCK_TYPE_UNKNOWN 0
-/** The source of the time value reported by GPS clock is the local hardware clock. */
+/**
+ * The source of the time value reported by GPS clock is the local hardware
+ * clock. This is a mandatory flag. When the GpsSystemInfo's year_of_hw is 2016
+ * or higher, it is mandatory that 'time' is populated with the local hardware
+ * clock value, and this flag must always be set.
+ */
#define GPS_CLOCK_TYPE_LOCAL_HW_TIME 1
/**
* The source of the time value reported by GPS clock is the GPS time derived from satellites
@@ -296,7 +306,12 @@
#define GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY (1<<16)
/** A valid 'used in fix' flag is stored in the data structure. */
#define GPS_MEASUREMENT_HAS_USED_IN_FIX (1<<17)
-/** The value of 'pseudorange rate' is uncorrected. */
+/**
+ * The value of 'pseudorange rate' is uncorrected.
+ * This is a mandatory flag. It is mandatory that 'pseudorange rate' is
+ * populated with the uncorrected value, and this flag must always be set.
+ * See comments of GpsMeasurement::pseudorange_rate_mps for more details.
+ */
#define GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE (1<<18)
/**
@@ -316,9 +331,9 @@
typedef uint8_t GpsMultipathIndicator;
/** The indicator is not available or unknown. */
#define GPS_MULTIPATH_INDICATOR_UNKNOWN 0
-/** The measurement has been indicated to use multipath. */
+/** The measurement is indicated to be affected by multipath. */
#define GPS_MULTIPATH_INDICATOR_DETECTED 1
-/** The measurement has been indicated Not to use multipath. */
+/** The measurement is indicated to be not affected by multipath. */
#define GPS_MULTIPATH_INDICATOR_NOT_USED 2
/**
@@ -377,6 +392,27 @@
#define NAV_MESSAGE_STATUS_PARITY_REBUILT (1<<1)
/**
+ * Flag that indicates which extra data GnssSvInfo includes.
+ */
+typedef uint8_t GnssSvFlags;
+#define GNSS_SV_FLAGS_NONE 0
+#define GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA (1 << 0)
+#define GNSS_SV_FLAGS_HAS_ALMANAC_DATA (1 << 1)
+#define GNSS_SV_FLAGS_USED_IN_FIX (1 << 2)
+
+/**
+ * Constellation type of GnssSvInfo
+ */
+typedef uint8_t GnssConstellationType;
+#define GNSS_CONSTELLATION_UNKNOWN 0
+#define GNSS_CONSTELLATION_GPS 1
+#define GNSS_CONSTELLATION_SBAS 2
+#define GNSS_CONSTELLATION_GLONASS 3
+#define GNSS_CONSTELLATION_QZSS 4
+#define GNSS_CONSTELLATION_BEIDOU 5
+#define GNSS_CONSTELLATION_GALILEO 6
+
+/**
* Name for the GPS XTRA interface.
*/
#define GPS_XTRA_INTERFACE "gps-xtra"
@@ -437,8 +473,9 @@
double latitude;
/** Represents longitude in degrees. */
double longitude;
- /** Represents altitude in meters above the WGS 84 reference
- * ellipsoid. */
+ /**
+ * Represents altitude in meters above the WGS 84 reference ellipsoid.
+ */
double altitude;
/** Represents speed in meters per second. */
float speed;
@@ -471,43 +508,124 @@
float azimuth;
} GpsSvInfo;
-/** Represents SV status. */
typedef struct {
- /** set to sizeof(GpsSvStatus) */
- size_t size;
-
- /** Number of SVs currently visible. */
- int num_svs;
-
- /** Contains an array of SV information. */
- GpsSvInfo sv_list[GPS_MAX_SVS];
-
- /** Represents a bit mask indicating which SVs
- * have ephemeris data.
- */
- uint32_t ephemeris_mask;
-
- /** Represents a bit mask indicating which SVs
- * have almanac data.
- */
- uint32_t almanac_mask;
+ /** set to sizeof(GnssSvInfo) */
+ size_t size;
/**
- * Represents a bit mask indicating which SVs
- * were used for computing the most recent position fix.
+ * Pseudo-random number for the SV, or Amanac/slot number for Glonass. The
+ * distinction is made by looking at constellation field. Values should be
+ * in the range of:
+ *
+ * - GPS: 1-32
+ * - SBAS: 120-151, 183-192
+ * - GLONASS: 1-24 (slot number)
+ * - QZSS: 193-200
+ * - Galileo: 1-25
+ * - Beidou: 1-35
*/
- uint32_t used_in_fix_mask;
+ int prn;
+
+ /** Signal to noise ratio. */
+ float snr;
+
+ /** Elevation of SV in degrees. */
+ float elevation;
+
+ /** Azimuth of SV in degrees. */
+ float azimuth;
+
+ /**
+ * Contains additional data about the given SV. Value should be one of those
+ * GNSS_SV_FLAGS_* constants
+ */
+ GnssSvFlags flags;
+
+ /**
+ * Defines the constellation of the given SV. Value should be one of those
+ * GNSS_CONSTELLATION_* constants
+ */
+ GnssConstellationType constellation;
+
+} GnssSvInfo;
+
+/**
+ * Represents SV status.
+ *
+ * When switching from pre-N to N version of GpsSvStatus:
+ *
+ * 1) Fill in the fields from num_svs through used_in_fix_mask the same way as
+ * was done before, e.g. using the range of 65-88 to report Glonass info,
+ * 201-235 for Beidou, etc. (but with no used_in_fix_mask info - those are
+ * index by prn, and thus for GPS only). This will help ensure compatibility
+ * when a newer GPS HAL is used with an older version of Android.
+ *
+ * 2) Fill in the gnss_sv_list with information about SVs from all
+ * constellations (GPS & other GNSS's) - when this is filled in, this will be
+ * the only source of information about satellite status (e.g. for working with
+ * GpsStatus facing applications), the earlier fields will be ignored.
+ */
+typedef struct {
+ /** set to sizeof(GpsSvStatus) */
+ size_t size;
+
+ /** Number of GPS SVs currently visible, refers to the SVs stored in sv_list */
+ int num_svs;
+
+ /** Contains an array of GPS SV information in legacy GPS format. */
+ GpsSvInfo sv_list[GPS_MAX_SVS];
+
+ /**
+ * Represents a bit mask indicating which GPS SVs have ephemeris data,
+ * refers to sv_list.
+ */
+ uint32_t ephemeris_mask;
+
+ /**
+ * Represents a bit mask indicating which GPS SVs have almanac data, refers
+ * to sv_list.
+ */
+ uint32_t almanac_mask;
+
+ /**
+ * Represents a bit mask indicating which GPS SVs
+ * were used for computing the most recent position fix,
+ * refers to sv_list.
+ */
+ uint32_t used_in_fix_mask;
+
+ /**
+ * Size of the array which contains SV info for all GNSS constellation
+ * except for GPS.
+ */
+ size_t gnss_sv_list_size;
+
+ /**
+ * Pointer to an array of SVs information for all GNSS constellations,
+ * except GPS, which is reported using sv_list
+ */
+ GnssSvInfo* gnss_sv_list;
+
} GpsSvStatus;
-
-/* 2G and 3G */
-/* In 3G lac is discarded */
+/* CellID for 2G, 3G and LTE, used in AGPS. */
typedef struct {
- uint16_t type;
+ AGpsRefLocationType type;
+ /** Mobile Country Code. */
uint16_t mcc;
+ /** Mobile Network Code .*/
uint16_t mnc;
+ /** Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE,
+ * lac is populated with tac, to ensure that we don't break old clients that
+ * might rely in the old (wrong) behavior.
+ */
uint16_t lac;
+ /** Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */
uint32_t cid;
+ /** Tracking Area Code in LTE. */
+ uint16_t tac;
+ /** Physical Cell id in LTE (not used in 2G and 3G) */
+ uint16_t pcid;
} AGpsRefLocationCellID;
typedef struct {
@@ -516,20 +634,22 @@
/** Represents ref locations */
typedef struct {
- uint16_t type;
+ AGpsRefLocationType type;
union {
AGpsRefLocationCellID cellID;
AGpsRefLocationMac mac;
} u;
} AGpsRefLocation;
-/** Callback with location information.
- * Can only be called from a thread created by create_thread_cb.
+/**
+ * Callback with location information. Can only be called from a thread created
+ * by create_thread_cb.
*/
typedef void (* gps_location_callback)(GpsLocation* location);
-/** Callback with status information.
- * Can only be called from a thread created by create_thread_cb.
+/**
+ * Callback with status information. Can only be called from a thread created by
+ * create_thread_cb.
*/
typedef void (* gps_status_callback)(GpsStatus* status);
@@ -539,18 +659,21 @@
*/
typedef void (* gps_sv_status_callback)(GpsSvStatus* sv_info);
-/** Callback for reporting NMEA sentences.
- * Can only be called from a thread created by create_thread_cb.
+/**
+ * Callback for reporting NMEA sentences. Can only be called from a thread
+ * created by create_thread_cb.
*/
typedef void (* gps_nmea_callback)(GpsUtcTime timestamp, const char* nmea, int length);
-/** Callback to inform framework of the GPS engine's capabilities.
- * Capability parameter is a bit field of GPS_CAPABILITY_* flags.
+/**
+ * Callback to inform framework of the GPS engine's capabilities. Capability
+ * parameter is a bit field of GPS_CAPABILITY_* flags.
*/
typedef void (* gps_set_capabilities)(uint32_t capabilities);
-/** Callback utility for acquiring the GPS wakelock.
- * This can be used to prevent the CPU from suspending while handling GPS events.
+/**
+ * Callback utility for acquiring the GPS wakelock. This can be used to prevent
+ * the CPU from suspending while handling GPS events.
*/
typedef void (* gps_acquire_wakelock)();
@@ -560,12 +683,57 @@
/** Callback for requesting NTP time */
typedef void (* gps_request_utc_time)();
-/** Callback for creating a thread that can call into the Java framework code.
- * This must be used to create any threads that report events up to the framework.
+/**
+ * Callback for creating a thread that can call into the Java framework code.
+ * This must be used to create any threads that report events up to the
+ * framework.
*/
typedef pthread_t (* gps_create_thread)(const char* name, void (*start)(void *), void* arg);
-/** GPS callback structure. */
+/**
+ * Provides information about how new the underlying GPS/GNSS hardware and
+ * software is.
+ *
+ * This information will be available for Android Test Applications. If a GPS
+ * HAL does not provide this information, it will be considered "2015 or
+ * earlier".
+ *
+ * If a GPS HAL does provide this information, then newer years will need to
+ * meet newer CTS standards. E.g. if the date are 2016 or above, then N+ level
+ * GpsMeasurement support will be verified.
+ */
+typedef struct {
+ /** Set to sizeof(GpsSystemInfo) */
+ size_t size;
+ /* year in which the last update was made to the underlying hardware/firmware
+ * used to capture GNSS signals, e.g. 2016 */
+ uint16_t year_of_hw;
+} GpsSystemInfo;
+
+/**
+ * Callback to inform framework of the engine's hardware version information.
+ */
+typedef void (*gps_set_system_info)(const GpsSystemInfo* info);
+
+/**
+ * Legacy GPS callback structure.
+ * See GpsCallbacks for more information.
+ */
+typedef struct {
+ /** set to sizeof(GpsCallbacks_v1) */
+ size_t size;
+ gps_location_callback location_cb;
+ gps_status_callback status_cb;
+ gps_sv_status_callback sv_status_cb;
+ gps_nmea_callback nmea_cb;
+ gps_set_capabilities set_capabilities_cb;
+ gps_acquire_wakelock acquire_wakelock_cb;
+ gps_release_wakelock release_wakelock_cb;
+ gps_create_thread create_thread_cb;
+ gps_request_utc_time request_utc_time_cb;
+} GpsCallbacks_v1;
+
+/** New GPS callback structure. */
typedef struct {
/** set to sizeof(GpsCallbacks) */
size_t size;
@@ -578,8 +746,17 @@
gps_release_wakelock release_wakelock_cb;
gps_create_thread create_thread_cb;
gps_request_utc_time request_utc_time_cb;
-} GpsCallbacks;
+ /**
+ * Callback for the chipset to report system information.
+ *
+ * This field is newly introduced since N. The driver implementation must
+ * check 'size' field against 'sizeof(GpsCallbacks)' and
+ * 'sizeof(GpsCallbacks_v1)' to decide whether the new field is valid before
+ * calling it.
+ */
+ gps_set_system_info set_system_info_cb;
+} GpsCallbacks;
/** Represents the standard GPS interface. */
typedef struct {
@@ -604,10 +781,10 @@
int (*inject_time)(GpsUtcTime time, int64_t timeReference,
int uncertainty);
- /** Injects current location from another location provider
- * (typically cell ID).
- * latitude and longitude are measured in degrees
- * expected accuracy is measured in meters
+ /**
+ * Injects current location from another location provider (typically cell
+ * ID). Latitude and longitude are measured in degrees expected accuracy is
+ * measured in meters
*/
int (*inject_location)(double latitude, double longitude, float accuracy);
@@ -623,10 +800,10 @@
* preferred_accuracy represents the requested fix accuracy in meters.
* preferred_time represents the requested time to first fix in milliseconds.
*
- * 'mode' parameter should be one of GPS_POSITION_MODE_MS_BASE
+ * 'mode' parameter should be one of GPS_POSITION_MODE_MS_BASED
* or GPS_POSITION_MODE_STANDALONE.
* It is allowed by the platform (and it is recommended) to fallback to
- * GPS_POSITION_MODE_MS_BASE if GPS_POSITION_MODE_MS_ASSISTED is passed in, and
+ * GPS_POSITION_MODE_MS_BASED if GPS_POSITION_MODE_MS_ASSISTED is passed in, and
* GPS_POSITION_MODE_MS_BASED is supported.
*/
int (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,
@@ -636,9 +813,10 @@
const void* (*get_extension)(const char* name);
} GpsInterface;
-/** Callback to request the client to download XTRA data.
- * The client should download XTRA data and inject it by calling inject_xtra_data().
- * Can only be called from a thread created by create_thread_cb.
+/**
+ * Callback to request the client to download XTRA data. The client should
+ * download XTRA data and inject it by calling inject_xtra_data(). Can only be
+ * called from a thread created by create_thread_cb.
*/
typedef void (* gps_xtra_download_request)();
@@ -673,36 +851,11 @@
size_t (*get_internal_state)(char* buffer, size_t bufferSize);
} GpsDebugInterface;
-#pragma pack(push,4)
-// We need to keep the alignment of this data structure to 4-bytes, to ensure that in 64-bit
-// environments the size of this legacy definition does not collide with _v2. Implementations should
-// be using _v2 and _v3, so it's OK to pay the 'unaligned' penalty in 64-bit if an old
-// implementation is still in use.
-
-/** Represents the status of AGPS. */
+/*
+ * Represents the status of AGPS augmented to support IPv4 and IPv6.
+ */
typedef struct {
- /** set to sizeof(AGpsStatus_v1) */
- size_t size;
-
- AGpsType type;
- AGpsStatusValue status;
-} AGpsStatus_v1;
-
-#pragma pack(pop)
-
-/** Represents the status of AGPS augmented with a IPv4 address field. */
-typedef struct {
- /** set to sizeof(AGpsStatus_v2) */
- size_t size;
-
- AGpsType type;
- AGpsStatusValue status;
- uint32_t ipaddr;
-} AGpsStatus_v2;
-
-/* Represents the status of AGPS augmented to support IPv4 and IPv6. */
-typedef struct {
- /** set to sizeof(AGpsStatus_v3) */
+ /** set to sizeof(AGpsStatus) */
size_t size;
AGpsType type;
@@ -717,14 +870,13 @@
/**
* Must contain the IPv4 (AF_INET) or IPv6 (AF_INET6) address to report.
* Any other value of addr.ss_family will be rejected.
- * */
+ */
struct sockaddr_storage addr;
-} AGpsStatus_v3;
+} AGpsStatus;
-typedef AGpsStatus_v3 AGpsStatus;
-
-/** Callback with AGPS status information.
- * Can only be called from a thread created by create_thread_cb.
+/**
+ * Callback with AGPS status information. Can only be called from a thread
+ * created by create_thread_cb.
*/
typedef void (* agps_status_callback)(AGpsStatus* status);
@@ -734,42 +886,12 @@
gps_create_thread create_thread_cb;
} AGpsCallbacks;
-
-/** Extended interface for AGPS support. */
-typedef struct {
- /** set to sizeof(AGpsInterface_v1) */
- size_t size;
-
- /**
- * Opens the AGPS interface and provides the callback routines
- * to the implementation of this interface.
- */
- void (*init)( AGpsCallbacks* callbacks );
- /**
- * Notifies that a data connection is available and sets
- * the name of the APN to be used for SUPL.
- */
- int (*data_conn_open)( const char* apn );
- /**
- * Notifies that the AGPS data connection has been closed.
- */
- int (*data_conn_closed)();
- /**
- * Notifies that a data connection is not available for AGPS.
- */
- int (*data_conn_failed)();
- /**
- * Sets the hostname and port for the AGPS server.
- */
- int (*set_server)( AGpsType type, const char* hostname, int port );
-} AGpsInterface_v1;
-
/**
* Extended interface for AGPS support, it is augmented to enable to pass
* extra APN data.
*/
typedef struct {
- /** set to sizeof(AGpsInterface_v2) */
+ /** set to sizeof(AGpsInterface) */
size_t size;
/**
@@ -803,9 +925,7 @@
int (*data_conn_open_with_apn_ip_type)(
const char* apn,
ApnIpType apnIpType);
-} AGpsInterface_v2;
-
-typedef AGpsInterface_v2 AGpsInterface;
+} AGpsInterface;
/** Error codes associated with certificate operations */
#define AGPS_CERTIFICATE_OPERATION_SUCCESS 0
@@ -936,8 +1056,9 @@
} GpsNiNotification;
-/** Callback with NI notification.
- * Can only be called from a thread created by create_thread_cb.
+/**
+ * Callback with NI notification. Can only be called from a thread created by
+ * create_thread_cb.
*/
typedef void (*gps_ni_notify_callback)(GpsNiNotification *notification);
@@ -1280,7 +1401,6 @@
void (*remove_geofence_area) (int32_t geofence_id);
} GpsGeofencingInterface;
-
/**
* Represents an estimate of the GPS clock time.
*/
@@ -1302,7 +1422,7 @@
/**
* Indicates the type of time reported by the 'time_ns' field.
- * This is a Mandatory field.
+ * This is a mandatory field.
*/
GpsClockType type;
@@ -1321,7 +1441,11 @@
* Sub-nanosecond accuracy can be provided by means of the 'bias' field.
* The value contains the 'time uncertainty' in it.
*
- * This is a Mandatory field.
+ * This field is mandatory.
+ *
+ * For devices where GpsSystemInfo's year_of_hw is set to 2016+, it is
+ * mandatory that it contains the value from the 'local hardware clock, and
+ * thus GPS_CLOCK_TYPE_LOCAL_HW_TIME must be set in 'type' field.
*/
int64_t time_ns;
@@ -1329,8 +1453,9 @@
* 1-Sigma uncertainty associated with the clock's time in nanoseconds.
* The uncertainty is represented as an absolute (single sided) value.
*
- * This value should be set if GPS_CLOCK_TYPE_GPS_TIME is set.
- * If the data is available 'flags' must contain GPS_CLOCK_HAS_TIME_UNCERTAINTY.
+ * If the data is available, 'flags' must contain
+ * GPS_CLOCK_HAS_TIME_UNCERTAINTY. If GPS has computed a position fix, this
+ * field is mandatory and must be populated.
*/
double time_uncertainty_ns;
@@ -1345,8 +1470,9 @@
* true time (GPS time) = time_ns + (full_bias_ns + bias_ns)
*
* This value contains the 'bias uncertainty' in it.
- * If the data is available 'flags' must contain GPS_CLOCK_HAS_FULL_BIAS.
-
+ * If GPS has computed a position fix this field is mandatory and must be
+ * populated. If the data is available 'flags' must contain
+ * GPS_CLOCK_HAS_FULL_BIAS.
*/
int64_t full_bias_ns;
@@ -1354,7 +1480,9 @@
* Sub-nanosecond bias.
* The value contains the 'bias uncertainty' in it.
*
- * If the data is available 'flags' must contain GPS_CLOCK_HAS_BIAS.
+ * If the data is available 'flags' must contain GPS_CLOCK_HAS_BIAS. If GPS
+ * has computed a position fix, this field is mandatory and must be
+ * populated.
*/
double bias_ns;
@@ -1362,7 +1490,9 @@
* 1-Sigma uncertainty associated with the clock's bias in nanoseconds.
* The uncertainty is represented as an absolute (single sided) value.
*
- * If the data is available 'flags' must contain GPS_CLOCK_HAS_BIAS_UNCERTAINTY.
+ * If the data is available 'flags' must contain
+ * GPS_CLOCK_HAS_BIAS_UNCERTAINTY. If GPS has computed a position fix this
+ * field is mandatory and must be populated.
*/
double bias_uncertainty_ns;
@@ -1373,8 +1503,10 @@
* The value contains the 'drift uncertainty' in it.
* If the data is available 'flags' must contain GPS_CLOCK_HAS_DRIFT.
*
- * If GpsMeasurement's 'flags' field contains GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE,
- * it is encouraged that this field is also provided.
+ * If GpsMeasurement's 'flags' field contains
+ * GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE, it is encouraged that
+ * this field is also provided. If GPS has computed a position fix this
+ * field is mandatory and must be populated.
*/
double drift_nsps;
@@ -1382,9 +1514,30 @@
* 1-Sigma uncertainty associated with the clock's drift in nanoseconds (per second).
* The uncertainty is represented as an absolute (single sided) value.
*
- * If the data is available 'flags' must contain GPS_CLOCK_HAS_DRIFT_UNCERTAINTY.
+ * If the data is available 'flags' must contain
+ * GPS_CLOCK_HAS_DRIFT_UNCERTAINTY. If GPS has computed a position fix this
+ * field is mandatory and must be populated.
*/
double drift_uncertainty_nsps;
+
+ /**
+ * When the GPS_CLOCK_TYPE_LOCAL_HW_TIME is set, this field is mandatory.
+ *
+ * A "discontinuity" is meant to cover the case of a switch from one source
+ * of clock to another. A single free-running crystal oscillator (XO)
+ * should generally not have any discontinuities, and this can be set to 0.
+ * If, however, the time_ns value (HW clock) is derived from a composite of
+ * sources, that is not as smooth as a typical XO, then this value shall be
+ * set to the time_ns value since which the time_ns has been derived from a
+ * single, high quality clock (XO like, or better, that's typically used
+ * during continuous GPS signal sampling.)
+ *
+ * It is expected, esp. during periods where there are few GNSS signals
+ * available, that the HW clock be discontinuity-free as long as possible,
+ * as this avoids the need to use (waste) a GPS measurement to fully
+ * re-solve for the clock bias and drift.
+ */
+ int64_t time_of_last_hw_clock_discontinuity_ns;
} GpsClock;
/**
@@ -1399,7 +1552,7 @@
/**
* Pseudo-random number in the range of [1, 32]
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
int8_t prn;
@@ -1412,7 +1565,7 @@
* measurement time = GpsClock::time_ns + time_offset_ns
*
* It provides an individual time-stamp for the measurement, and allows sub-nanosecond accuracy.
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
double time_offset_ns;
@@ -1420,7 +1573,7 @@
* Per satellite sync state. It represents the current sync state for the associated satellite.
* Based on the sync state, the 'received GPS tow' field should be interpreted accordingly.
*
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
GpsMeasurementState state;
@@ -1454,7 +1607,7 @@
* Carrier-to-noise density in dB-Hz, in the range [0, 63].
* It contains the measured C/N0 value for the signal at the antenna input.
*
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
double c_n0_dbhz;
@@ -1463,13 +1616,9 @@
* The correction of a given Pseudorange Rate value includes corrections for receiver and
* satellite clock frequency errors.
*
- * If GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE is set in 'flags' field, this field must
- * be populated with the 'uncorrected' reading.
- * If GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE is not set in 'flags' field, this field
- * must be populated with the 'corrected' reading. This is the default behavior.
- *
* It is encouraged to provide the 'uncorrected' 'pseudorange rate', and provide GpsClock's
- * 'drift' field as well.
+ * 'drift' field as well. When providing the uncorrected pseudorange rate,
+ * do not apply the corrections described above.
*
* The value includes the 'pseudorange rate uncertainty' in it.
* A positive 'uncorrected' value indicates that the SV is moving away from the receiver.
@@ -1478,15 +1627,22 @@
* shift' is given by the equation:
* pseudorange rate = -k * doppler shift (where k is a constant)
*
- * This is a Mandatory value.
+ * This field should be based on the signal energy doppler measurement. (See
+ * also pseudorate_rate_carrier_mps for a similar field, based on carrier
+ * phase changes.)
+ *
+ * This is a mandatory value. It is mandatory (and expected) that it
+ * contains the 'uncorrected' reading, and
+ * GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE must be set in 'flags'
+ * field.
*/
double pseudorange_rate_mps;
/**
- * 1-Sigma uncertainty of the pseudurange rate in m/s.
+ * 1-Sigma uncertainty of the pseudorange_rate_mps.
* The uncertainty is represented as an absolute (single sided) value.
*
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
double pseudorange_rate_uncertainty_mps;
@@ -1494,7 +1650,7 @@
* Accumulated delta range's state. It indicates whether ADR is reset or there is a cycle slip
* (indicating loss of lock).
*
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
GpsAccumulatedDeltaRangeState accumulated_delta_range_state;
@@ -1651,7 +1807,7 @@
* Azimuth in degrees, in the range [0, 360).
* The value contains the 'azimuth uncertainty' in it.
* If the data is available, 'flags' must contain GPS_MEASUREMENT_HAS_AZIMUTH.
- * */
+ */
double azimuth_deg;
/**
@@ -1667,6 +1823,41 @@
* If the data is available, 'flags' must contain GPS_MEASUREMENT_HAS_USED_IN_FIX.
*/
bool used_in_fix;
+
+ /**
+ * Pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
+ *
+ * The correction of a given Pseudorange Rate value includes corrections for
+ * receiver and satellite clock frequency errors.
+ *
+ * It is mandatory to provide the 'uncorrected' 'pseudorange rate' in this
+ * field. (Do not apply the corrections described above.)
+ *
+ * The value includes the 'pseudorange rate (carrier) uncertainty' in it. A
+ * positive 'uncorrected' value indicates that the SV is moving away from
+ * the receiver.
+ *
+ * The sign of the 'uncorrected' 'pseudorange rate' and its relation to the
+ * sign of 'doppler shift' is given by the equation:
+ *
+ * pseudorange rate = -k * doppler shift (where k is a constant)
+ *
+ * This field must be based on changes in the carrier phase measurement.
+ * (See pseudorange_rate_mps for a similar field, based on signal energy
+ * doppler.)
+ *
+ * It is mandatory that this value be provided, when signals are
+ * sufficiently strong, e.g. signals from a GPS simulator at >= 30 dB-Hz.
+ */
+ double pseudorange_rate_carrier_mps;
+ /**
+ * 1-Sigma uncertainty of the pseudorange_rate_carrier_mps.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * This is a mandatory value when pseudorange_rate_carrier_mps is provided.
+ */
+ double pseudorange_rate_carrier_uncertainty_mps;
+
} GpsMeasurement;
/** Represents a reading of GPS measurements. */
@@ -1740,13 +1931,13 @@
/**
* Pseudo-random number in the range of [1, 32]
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
int8_t prn;
/**
* The type of message contained in the structure.
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
GpsNavigationMessageType type;
@@ -1778,7 +1969,7 @@
* If this value is different from zero, 'data' must point to an array of the same size.
* e.g. for L1 C/A the size of the sub-frame will be 40 bytes (10 words, 30 bits/word).
*
- * This is a Mandatory value.
+ * This is a mandatory value.
*/
size_t data_length;
diff --git a/include/hardware/gps_internal.h b/include/hardware/gps_internal.h
new file mode 100644
index 0000000..cd83636
--- /dev/null
+++ b/include/hardware/gps_internal.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 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_GPS_INTERNAL_H
+#define ANDROID_INCLUDE_HARDWARE_GPS_INTERNAL_H
+
+#include "hardware/gps.h"
+
+/****************************************************************************
+ * This file contains legacy structs that are deprecated/retired from gps.h *
+ ****************************************************************************/
+
+__BEGIN_DECLS
+
+/**
+ * Legacy struct to represent SV status.
+ * See GpsSvStatus_v2 for more information.
+ */
+typedef struct {
+ /** set to sizeof(GpsSvStatus_v1) */
+ size_t size;
+ int num_svs;
+ GpsSvInfo sv_list[GPS_MAX_SVS];
+ uint32_t ephemeris_mask;
+ uint32_t almanac_mask;
+ uint32_t used_in_fix_mask;
+} GpsSvStatus_v1;
+
+#pragma pack(push,4)
+// We need to keep the alignment of this data structure to 4-bytes, to ensure that in 64-bit
+// environments the size of this legacy definition does not collide with _v2. Implementations should
+// be using _v2 and _v3, so it's OK to pay the 'unaligned' penalty in 64-bit if an old
+// implementation is still in use.
+
+/**
+ * Legacy struct to represent the status of AGPS.
+ */
+typedef struct {
+ /** set to sizeof(AGpsStatus_v1) */
+ size_t size;
+ AGpsType type;
+ AGpsStatusValue status;
+} AGpsStatus_v1;
+
+#pragma pack(pop)
+
+/**
+ * Legacy struct to represent the status of AGPS augmented with a IPv4 address
+ * field.
+ */
+typedef struct {
+ /** set to sizeof(AGpsStatus_v2) */
+ size_t size;
+ AGpsType type;
+ AGpsStatusValue status;
+
+ /*-------------------- New fields in _v2 --------------------*/
+
+ uint32_t ipaddr;
+} AGpsStatus_v2;
+
+/**
+ * Legacy extended interface for AGPS support.
+ * See AGpsInterface_v2 for more information.
+ */
+typedef struct {
+ /** set to sizeof(AGpsInterface_v1) */
+ size_t size;
+ void (*init)( AGpsCallbacks* callbacks );
+ int (*data_conn_open)( const char* apn );
+ int (*data_conn_closed)();
+ int (*data_conn_failed)();
+ int (*set_server)( AGpsType type, const char* hostname, int port );
+} AGpsInterface_v1;
+
+/**
+ * Legacy struct to represent an estimate of the GPS clock time.
+ * See GpsClock_v2 for more details.
+ */
+typedef struct {
+ /** set to sizeof(GpsClock_v1) */
+ size_t size;
+ GpsClockFlags flags;
+ int16_t leap_second;
+ GpsClockType type;
+ int64_t time_ns;
+ double time_uncertainty_ns;
+ int64_t full_bias_ns;
+ double bias_ns;
+ double bias_uncertainty_ns;
+ double drift_nsps;
+ double drift_uncertainty_nsps;
+} GpsClock_v1;
+
+/**
+ * Legacy struct to represent a GPS Measurement, it contains raw and computed
+ * information.
+ * See GpsMeasurement_v2 for more details.
+ */
+typedef struct {
+ /** set to sizeof(GpsMeasurement_v1) */
+ size_t size;
+ GpsMeasurementFlags flags;
+ int8_t prn;
+ double time_offset_ns;
+ GpsMeasurementState state;
+ int64_t received_gps_tow_ns;
+ int64_t received_gps_tow_uncertainty_ns;
+ double c_n0_dbhz;
+ double pseudorange_rate_mps;
+ double pseudorange_rate_uncertainty_mps;
+ GpsAccumulatedDeltaRangeState accumulated_delta_range_state;
+ double accumulated_delta_range_m;
+ double accumulated_delta_range_uncertainty_m;
+ double pseudorange_m;
+ double pseudorange_uncertainty_m;
+ double code_phase_chips;
+ double code_phase_uncertainty_chips;
+ float carrier_frequency_hz;
+ int64_t carrier_cycles;
+ double carrier_phase;
+ double carrier_phase_uncertainty;
+ GpsLossOfLock loss_of_lock;
+ int32_t bit_number;
+ int16_t time_from_last_bit_ms;
+ double doppler_shift_hz;
+ double doppler_shift_uncertainty_hz;
+ GpsMultipathIndicator multipath_indicator;
+ double snr_db;
+ double elevation_deg;
+ double elevation_uncertainty_deg;
+ double azimuth_deg;
+ double azimuth_uncertainty_deg;
+ bool used_in_fix;
+} GpsMeasurement_v1;
+
+/** Represents a reading of GPS measurements. */
+typedef struct {
+ /** set to sizeof(GpsData_v1) */
+ size_t size;
+
+ /** Number of measurements. */
+ size_t measurement_count;
+
+ /** The array of measurements. */
+ GpsMeasurement_v1 measurements[GPS_MAX_MEASUREMENT];
+
+ /** The GPS clock time reading. */
+ GpsClock_v1 clock;
+} GpsData_v1;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_HARDWARE_GPS_INTERNAL_H */
diff --git a/include/hardware/hardware_properties.h b/include/hardware/hardware_properties.h
new file mode 100644
index 0000000..7c9bd4e
--- /dev/null
+++ b/include/hardware/hardware_properties.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 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_HARDWAREPROPERTIES_H
+#define ANDROID_INCLUDE_HARDWARE_HARDWAREPROPERTIES_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <hardware/hardware.h>
+
+__BEGIN_DECLS
+
+#define HARDWARE_PROPERTIES_HARDWARE_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
+
+/**
+ * The id of this module
+ */
+#define HARDWARE_PROPERTIES_HARDWARE_MODULE_ID "hardware_properties"
+
+/**
+ * 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 hardware_properties_module {
+ struct hw_module_t common;
+
+ /*
+ * (*getCpuTemperatures) is called to get CPU temperatures in Celsius of
+ * each core.
+ *
+ * Returns number of cores or negative value on error.
+ *
+ */
+ ssize_t (*getCpuTemperatures)(struct hardware_properties_module *module, float **temps);
+
+ /*
+ * (*getGpuTemperatures) is called to get GPU temperatures in Celsius of
+ * each GPU.
+ *
+ * Returns number of GPUs or negative value on error.
+ *
+ */
+ ssize_t (*getGpuTemperatures)(struct hardware_properties_module *module, float **temps);
+
+ /*
+ * (*getBatteryTemperatures) is called to get battery temperatures in
+ * Celsius.
+ *
+ * Returns number of battery temperatures or negative value on error.
+ *
+ */
+ ssize_t (*getBatteryTemperatures)(struct hardware_properties_module *module, float **temps);
+
+ /*
+ * (*getCpuUsages) is called to get CPU usage information of each core:
+ * active and total times in ms since first boot.
+ *
+ * Returns number of cores or negative value on error.
+ *
+ */
+ ssize_t (*getCpuUsages)(struct hardware_properties_module *module,
+ int64_t **active_times, int64_t **total_times);
+
+ /*
+ * (*getFanSpeeds) is called to get the fan speeds in RPM of each fan.
+ *
+ * Returns number of fans or negative value on error.
+ *
+ */
+ ssize_t (*getFanSpeeds)(struct hardware_properties_module *module,
+ float **fan_speeds);
+} hardware_properties_module_t;
+
+__END_DECLS
+
+#endif // ANDROID_INCLUDE_HARDWARE_HARDWAREPROPERTIES_H
diff --git a/include/hardware/input.h b/include/hardware/input.h
index 969b8ce..c4a4cb5 100644
--- a/include/hardware/input.h
+++ b/include/hardware/input.h
@@ -318,6 +318,12 @@
// axes
INPUT_USAGE_AXIS_X,
INPUT_USAGE_AXIS_Y,
+ INPUT_USAGE_AXIS_Z,
+ INPUT_USAGE_AXIS_RX,
+ INPUT_USAGE_AXIS_RY,
+ INPUT_USAGE_AXIS_RZ,
+ INPUT_USAGE_AXIS_HAT_X,
+ INPUT_USAGE_AXIS_HAT_Y,
INPUT_USAGE_AXIS_PRESSURE,
INPUT_USAGE_AXIS_SIZE,
INPUT_USAGE_AXIS_TOUCH_MAJOR,
@@ -327,12 +333,6 @@
INPUT_USAGE_AXIS_ORIENTATION,
INPUT_USAGE_AXIS_VSCROLL,
INPUT_USAGE_AXIS_HSCROLL,
- INPUT_USAGE_AXIS_Z,
- INPUT_USAGE_AXIS_RX,
- INPUT_USAGE_AXIS_RY,
- INPUT_USAGE_AXIS_RZ,
- INPUT_USAGE_AXIS_HAT_X,
- INPUT_USAGE_AXIS_HAT_Y,
INPUT_USAGE_AXIS_LTRIGGER,
INPUT_USAGE_AXIS_RTRIGGER,
INPUT_USAGE_AXIS_THROTTLE,
@@ -375,13 +375,32 @@
INPUT_USAGE_LED_CONTROLLER_2,
INPUT_USAGE_LED_CONTROLLER_3,
INPUT_USAGE_LED_CONTROLLER_4,
+
+ // switches
+ INPUT_USAGE_SWITCH_UNKNOWN,
+ INPUT_USAGE_SWITCH_LID,
+ INPUT_USAGE_SWITCH_KEYPAD_SLIDE,
+ INPUT_USAGE_SWITCH_HEADPHONE_INSERT,
+ INPUT_USAGE_SWITCH_MICROPHONE_INSERT,
+ INPUT_USAGE_SWITCH_LINEOUT_INSERT,
+ INPUT_USAGE_SWITCH_CAMERA_LENS_COVER,
+
+ // mouse buttons
+ // (see android.view.MotionEvent)
+ INPUT_USAGE_BUTTON_UNKNOWN,
+ INPUT_USAGE_BUTTON_PRIMARY, // left
+ INPUT_USAGE_BUTTON_SECONDARY, // right
+ INPUT_USAGE_BUTTON_TERTIARY, // middle
+ INPUT_USAGE_BUTTON_FORWARD,
+ INPUT_USAGE_BUTTON_BACK,
} input_usage_t;
-typedef enum {
+typedef enum input_collection_id {
INPUT_COLLECTION_ID_TOUCH,
INPUT_COLLECTION_ID_KEYBOARD,
INPUT_COLLECTION_ID_MOUSE,
INPUT_COLLECTION_ID_TOUCHPAD,
+ INPUT_COLLECTION_ID_SWITCH,
// etc
} input_collection_id_t;
@@ -413,6 +432,11 @@
input_report_definition_t* (*create_output_report_definition)(input_host_t* host);
/**
+ * Frees the report definition.
+ */
+ void (*free_report_definition)(input_host_t* host, input_report_definition_t* report_def);
+
+ /**
* Append the report to the given input device.
*/
void (*input_device_definition_add_report)(input_host_t* host,
diff --git a/include/hardware/keymaster_defs.h b/include/hardware/keymaster_defs.h
index 5b5d2ec..c0ca514 100644
--- a/include/hardware/keymaster_defs.h
+++ b/include/hardware/keymaster_defs.h
@@ -536,7 +536,8 @@
#undef KEYMASTER_SIMPLE_COMPARE
inline void keymaster_free_param_values(keymaster_key_param_t* param, size_t param_count) {
- while (param_count-- > 0) {
+ while (param_count > 0) {
+ param_count--;
switch (keymaster_tag_get_type(param->tag)) {
case KM_BIGNUM:
case KM_BYTES:
diff --git a/include/hardware/lights.h b/include/hardware/lights.h
index 2cf5519..b426caf 100644
--- a/include/hardware/lights.h
+++ b/include/hardware/lights.h
@@ -30,6 +30,28 @@
*/
#define LIGHTS_HARDWARE_MODULE_ID "lights"
+/**
+ * Header file version.
+ */
+#define LIGHTS_HEADER_VERSION 1
+
+/**
+ * Device API version 0.0-1.0
+ *
+ * Base version for the device API in the lights HAL: all versions less than
+ * 2.0 are treated as being this version.
+ */
+#define LIGHTS_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION_2(1, 0, LIGHTS_HEADER_VERSION)
+
+/**
+ * Device API version 2.0
+ *
+ * Devices reporting this version or higher may additionally support the
+ * following modes:
+ * - BRIGHTNESS_MODE_LOW_PERSISTENCE
+ */
+#define LIGHTS_DEVICE_API_VERSION_2_0 HARDWARE_DEVICE_API_VERSION_2(2, 0, LIGHTS_HEADER_VERSION)
+
/*
* These light IDs correspond to logical lights, not physical.
* So for example, if your INDICATOR light is in line with your
@@ -82,6 +104,34 @@
#define BRIGHTNESS_MODE_SENSOR 1
/**
+ * Use a low-persistence mode for display backlights.
+ *
+ * When set, the device driver must switch to a mode optimized for low display
+ * persistence that is intended to be used when the device is being treated as a
+ * head mounted display (HMD). The actual display brightness in this mode is
+ * implementation dependent, and any value set for color in light_state may be
+ * overriden by the HAL implementation.
+ *
+ * For an optimal HMD viewing experience, the display should meet the following
+ * criteria in this mode:
+ * - Less than 2ms display persistence.
+ * - Any "smart panel" or other frame buffering options that increase display
+ * latency are disabled.
+ * - Display brightness is set so that the display is still visible to the user
+ * under normal indoor lighting.
+ *
+ * This mode will only be used with light devices of type LIGHT_ID_BACKLIGHT,
+ * and will only be called by the Android framework for light_device_t
+ * implementations that report a version >= 2.0 in their hw_device_t common
+ * fields. If the device version is >= 2.0 and this mode is unsupported, calling
+ * set_light with this mode must return the negative error code -ENOSYS (-38)
+ * without altering any settings.
+ *
+ * Available only for version >= LIGHTS_DEVICE_API_VERSION_2_0
+ */
+#define BRIGHTNESS_MODE_LOW_PERSISTENCE 2
+
+/**
* The parameters that can be set for a given light.
*
* Not all lights must support all parameters. If you
diff --git a/include/hardware/power.h b/include/hardware/power.h
index 10612f3..29ef4dc 100644
--- a/include/hardware/power.h
+++ b/include/hardware/power.h
@@ -28,6 +28,7 @@
#define POWER_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
#define POWER_MODULE_API_VERSION_0_2 HARDWARE_MODULE_API_VERSION(0, 2)
#define POWER_MODULE_API_VERSION_0_3 HARDWARE_MODULE_API_VERSION(0, 3)
+#define POWER_MODULE_API_VERSION_0_4 HARDWARE_MODULE_API_VERSION(0, 4)
/**
* The id of this module
@@ -46,7 +47,8 @@
*/
POWER_HINT_VIDEO_ENCODE = 0x00000003,
POWER_HINT_VIDEO_DECODE = 0x00000004,
- POWER_HINT_LOW_POWER = 0x00000005
+ POWER_HINT_LOW_POWER = 0x00000005,
+ POWER_HINT_SUSTAINED_PERFORMANCE = 0x00000006
} power_hint_t;
typedef enum {
@@ -126,6 +128,14 @@
* parameter is non-zero when low power mode is activated, and zero
* when deactivated.
*
+ * POWER_HINT_SUSTAINED_PERFORMANCE
+ *
+ * Sustained Performance mode is actived or deactivated. Sustained
+ * performance mode is intended to provide a consistent level of
+ * performance for a prolonged amount of time. The data parameter is
+ * non-zero when sustained performance mode is activated, and zero
+ * when deactivated.
+ *
* A particular platform may choose to ignore any hint.
*
* availability: version 0.2
diff --git a/include/hardware/sensors.h b/include/hardware/sensors.h
index 51bffe1..e59847e 100644
--- a/include/hardware/sensors.h
+++ b/include/hardware/sensors.h
@@ -657,6 +657,152 @@
#define SENSOR_TYPE_WRIST_TILT_GESTURE (26)
#define SENSOR_STRING_TYPE_WRIST_TILT_GESTURE "android.sensor.wrist_tilt_gesture"
+/*
+ * SENSOR_TYPE_DEVICE_ORIENTATION
+ * reporting-mode: on-change
+ *
+ * The current orientation of the device. The value should be reported in the
+ * first element of the 'data' member variable in sensors_event_t. The only
+ * values that can be reported are (please refer to Android Sensor Coordinate
+ * System to understand the X and Y axis direction with respect to default
+ * orientation):
+ * - 0: device is in default orientation (Y axis is vertical and points up)
+ * - 1: device is rotated 90 degrees counter-clockwise from default
+ * orientation (X axis is vertical and points up)
+ * - 2: device is rotated 180 degrees from default orientation (Y axis is
+ * vertical and points down)
+ * - 3: device is rotated 90 degrees clockwise from default orientation (X axis
+ * is vertical and points down)
+ *
+ * Moving the device to an orientation where the Z axis is vertical (either up
+ * or down) should not cause a new event to be reported.
+ *
+ * To improve the user experience of this sensor, it is recommended to implement
+ * some physical (i.e., rotation angle) and temporal (i.e., delay) hysteresis.
+ * In other words, minor or transient rotations should not cause a new event to
+ * be reported.
+ *
+ * This sensor should only be implemented with the help of an accelerometer.
+ * This is a low power sensor that should reduce the number of interrupts of the
+ * AP. Do not emulate this sensor in the HAL.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+#define SENSOR_TYPE_DEVICE_ORIENTATION (27)
+#define SENSOR_STRING_TYPE_DEVICE_ORIENTATION "android.sensor.device_orientation"
+
+/*
+ * SENSOR_TYPE_POSE_6DOF
+ * trigger-mode: continuous
+ *
+ * A sensor of this type returns the pose of the device.
+ * Pose of the device is defined as the orientation of the device from a
+ * Earth Centered Earth Fixed frame and the translation from an arbitrary
+ * point at subscription.
+ *
+ * This sensor can be high power. It can use any and all of the following
+ * . Accelerometer
+ * . Gyroscope
+ * . Camera
+ * . Depth Camera
+ *
+ */
+#define SENSOR_TYPE_POSE_6DOF (28)
+#define SENSOR_STRING_TYPE_POSE_6DOF "android.sensor.pose_6dof"
+
+/*
+ * SENSOR_TYPE_STATIONARY_DETECT
+ * trigger mode: one shot
+ *
+ * A sensor of this type returns an event if the device is still/stationary for
+ * a while. The period of time to monitor for statinarity should be greater than
+ * 5 seconds, and less than 10 seconds.
+ *
+ * Stationarity here refers to absolute stationarity. eg: device on desk.
+ *
+ * The only allowed value to return is 1.0.
+ */
+#define SENSOR_TYPE_STATIONARY_DETECT (29)
+#define SENSOR_STRING_TYPE_STATIONARY_DETECT "android.sensor.stationary_detect"
+
+/*
+ * SENSOR_TYPE_MOTION_DETECT
+ * trigger mode: one shot
+ *
+ * A sensor of this type returns an event if the device is not still for
+ * a while. The period of time to monitor for statinarity should be greater than
+ * 5 seconds, and less than 10 seconds.
+ *
+ * Motion here refers to any mechanism in which the device is causes to be
+ * moved in its inertial frame. eg: Pickin up the device and walking with it
+ * to a nearby room may trigger motion wherewas keeping the device on a table
+ * on a smooth train moving at constant velocity may not trigger motion.
+ *
+ * The only allowed value to return is 1.0.
+ */
+#define SENSOR_TYPE_MOTION_DETECT (30)
+#define SENSOR_STRING_TYPE_MOTION_DETECT "android.sensor.motion_detect"
+
+/*
+ * SENSOR_TYPE_HEART_BEAT
+ * trigger mode: continuous
+ *
+ * A sensor of this type returns an event everytime a hear beat peak is
+ * detected.
+ *
+ * Peak here ideally corresponds to the positive peak in the QRS complex of
+ * and ECG signal.
+ *
+ * The sensor is not expected to be optimized for latency. As a guide, a
+ * latency of up to 10 seconds is acceptable. However the timestamp attached
+ * to the event should be accurate and should correspond to the time the peak
+ * occured.
+ *
+ * The sensor event contains a parameter for the confidence in the detection
+ * of the peak where 0.0 represent no information at all, and 1.0 represents
+ * certainty.
+ */
+#define SENSOR_TYPE_HEART_BEAT (31)
+#define SENSOR_STRING_TYPE_HEART_BEAT "android.sensor.heart_beat"
+
+/**
+ * SENSOR_TYPE_DYNAMIC_SENSOR_META
+ * trigger-mode: special
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to or removed from the
+ * system. At most one sensor of this type can be present in one sensor HAL implementation and
+ * presence of a sensor of this type in sensor HAL implementation indicates that this sensor HAL
+ * supports dynamic sensor feature. Operations, such as batch, activate and setDelay, to this
+ * special purpose sensor should be treated as no-op and return successful.
+ *
+ * A dynamic sensor connection indicates connection of a physical device or instantiation of a
+ * virtual sensor backed by algorithm; and a dynamic sensor disconnection indicates the the
+ * opposite. A sensor event of SENSOR_TYPE_DYNAMIC_SENSOR_META type should be delivered regardless
+ * of the activation status of the sensor in the event of dynamic sensor connection and
+ * disconnection. In the sensor event, besides the common data entries, "dynamic_sensor_meta", which
+ * includes fields for connection status, handle of the sensor involved, pointer to sensor_t
+ * structure and a uuid field, should be populated.
+ *
+ * At a dynamic sensor connection event, fields of sensor_t structure referenced by a pointer in
+ * dynamic_sensor_meta should be filled as if it was regular sensors. Sensor HAL is responsible for
+ * recovery of memory if the corresponding data is dynamicially allocated. However, the the pointer
+ * must be valid until the first activate call to the sensor reported in this connection event. At a
+ * dynamic sensor disconnection, the sensor_t pointer should be NULL.
+ *
+ * The sensor handle assigned to dynamic sensors should never be the same as that of any regular
+ * static sensors, and should be unique until next boot. In another word, if a handle h is used for
+ * a dynamic sensor A, that same number cannot be used for the same dynamic sensor A or another
+ * dynamic sensor B even after disconnection of A until reboot.
+ *
+ * The UUID field will be used for identifying the sensor in addition to name, vendor and version
+ * and type. For physical sensors of the same model, all sensors will have the same values in
+ * sensor_t, but the UUID should be unique and persistent for each individual unit. An all zero UUID
+ * indicates it is not possible to differentiate individual sensor unit.
+ *
+ */
+#define SENSOR_TYPE_DYNAMIC_SENSOR_META (32)
+#define SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META "android.sensor.dynamic_sensor_meta"
+
/**
* Values returned by the accelerometer in various locations in the universe.
* all values are in SI units (m/s^2)
@@ -679,6 +825,9 @@
#define SENSOR_STATUS_ACCURACY_MEDIUM 2
#define SENSOR_STATUS_ACCURACY_HIGH 3
+
+struct sensor_t;
+
/**
* sensor event data
*/
@@ -731,6 +880,17 @@
} meta_data_event_t;
/**
+ * Dynamic sensor meta event. See the description of SENSOR_TYPE_DYNAMIC_SENSOR_META type for
+ * details.
+ */
+typedef struct dynamic_sensor_meta_event {
+ int32_t connected;
+ int32_t handle;
+ const struct sensor_t * sensor; // should be NULL if connected == false
+ uint8_t uuid[16]; // UUID of a dynamic sensor (use platform endianess).
+} dynamic_sensor_meta_event_t;
+
+/**
* Heart rate event data
*/
typedef struct {
@@ -809,6 +969,9 @@
* SENSOR_TYPE_META_DATA. The handle is ignored and must be zero.
*/
meta_data_event_t meta_data;
+
+ /* dynamic sensor meta event. See SENSOR_TYPE_DYNAMIC_SENSOR_META type for details */
+ dynamic_sensor_meta_event_t dynamic_sensor_meta;
};
union {
@@ -830,8 +993,6 @@
typedef sensors_event_t sensors_meta_data_event_t;
-struct sensor_t;
-
/**
* 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
diff --git a/include/hardware/tv_input.h b/include/hardware/tv_input.h
index ed3fafb..3bb9862 100644
--- a/include/hardware/tv_input.h
+++ b/include/hardware/tv_input.h
@@ -33,14 +33,18 @@
*
* Version History:
*
- * TV_INPUT_MODULE_API_VERSION_0_1:
- * Initial TV input hardware module API.
+ * TV_INPUT_DEVICE_API_VERSION_0_1:
+ * Initial TV input hardware device API.
+ *
+ * TV_INPUT_DEVICE_API_VERSION_0_2:
+ * Minor revision --- add video detection flag in stream configs.
*
*/
#define TV_INPUT_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
#define TV_INPUT_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION(0, 1)
+#define TV_INPUT_DEVICE_API_VERSION_0_2 HARDWARE_DEVICE_API_VERSION(0, 2)
/*
* The id of this module
@@ -164,7 +168,8 @@
* port. the framework regards input devices with no available streams as
* disconnected, so the implementation can generate this event with no
* available streams to indicate that this device is disconnected, and vice
- * versa.
+ * versa. In addition, streams have signal detection flag to denote if
+ * signal is detected for sure.
*/
TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED = 3,
/*
@@ -264,6 +269,33 @@
uint32_t max_video_height;
} tv_stream_config_t;
+enum {
+ /*
+ * Set if signal is detected on this stream. Note that even if this mask is
+ * unset it does not necessarily mean no signal --- it denotes that HAL is
+ * unsure of the signal status.
+ */
+ TV_STREAM_FLAG_MASK_SIGNAL_DETECTION = 0x1,
+};
+
+/*
+ * >= TV_INPUT_DEVICE_API_VERSION_0_2
+ *
+ * tv_stream_config_t extended in a way that allows extension without breaking
+ * binary compatibility
+ */
+typedef struct tv_stream_config_ext {
+ tv_stream_config_t config;
+
+ /*
+ * Flags to show the status of this stream. See TV_STREAM_FLAG_* for
+ * details.
+ */
+ uint32_t flags;
+
+ int32_t reserved[16 - 1];
+} tv_stream_config_ext_t;
+
typedef struct buffer_producer_stream {
/*
* IN/OUT: Width / height of the stream. Client may request for specific
@@ -397,7 +429,22 @@
int (*cancel_capture)(struct tv_input_device* dev, int device_id,
int stream_id, uint32_t seq);
- void* reserved[16];
+ /*
+ * get_stream_configurations_ext:
+ *
+ * Get stream configurations for a specific device. An input device may have
+ * multiple configurations.
+ *
+ * The configs object is guaranteed to be valid only until the next call to
+ * get_stream_configurations_ext() or STREAM_CONFIGURATIONS_CHANGED event.
+ *
+ * Return 0 on success.
+ */
+ int (*get_stream_configurations_ext)(const struct tv_input_device* dev,
+ int device_id, int* num_configurations,
+ const tv_stream_config_ext_t** configs);
+
+ void* reserved[16 - 1];
} tv_input_device_t;
__END_DECLS
diff --git a/include/hardware/vehicle.h b/include/hardware/vehicle.h
new file mode 100644
index 0000000..14fb7aa
--- /dev/null
+++ b/include/hardware/vehicle.h
@@ -0,0 +1,1599 @@
+/*
+ * Copyright (C) 2015 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_VEHICLE_INTERFACE_H
+#define ANDROID_VEHICLE_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include <hardware/hardware.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define VEHICLE_HEADER_VERSION 1
+#define VEHICLE_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
+#define VEHICLE_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION_2(1, 0, VEHICLE_HEADER_VERSION)
+
+/**
+ * Vehicle HAL to provide interfaces to various Car related sensors. The HAL is
+ * designed in a property, value maping where each property has a value which
+ * can be "get", "set" and "(un)subscribed" to. Subscribing will require the
+ * user of this HAL to provide parameters such as sampling rate.
+ */
+
+
+/*
+ * The id of this module
+ */
+#define VEHICLE_HARDWARE_MODULE_ID "vehicle"
+
+/**
+ * Name of the vehicle device to open
+ */
+#define VEHICLE_HARDWARE_DEVICE "vehicle_hw_device"
+
+/**
+ * Each vehicle property is defined with various annotations to specify the type of information.
+ * Annotations will be used by scripts to run some type check or generate some boiler-plate codes.
+ * Also the annotations are the specification for each property, and each HAL implementation should
+ * follow what is specified as annotations.
+ * Here is the list of annotations with explanation on what it does:
+ * @value_type: Type of data for this property. One of the value from vehicle_value_type should be
+ * set here.
+ * @change_mode: How this property changes. Value set is from vehicle_prop_change_mode. Some
+ * properties can allow either on change or continuous mode and it is up to HAL
+ * implementation to choose which mode to use.
+ * @access: Define how this property can be accessed. read only, write only or R/W from
+ * vehicle_prop_access
+ * @data_member: Name of member from vehicle_value union to access this data.
+ * @data_enum: enum type that should be used for the data.
+ * @unit: Unit of data. Should be from vehicle_unit_type.
+ * @config_flags: Usage of config_flags in vehicle_prop_config
+ * @config_array: Usage of config_array in vehicle_prop_config. When this is specified,
+ * @config_flags will not be used.
+ * @config_string: Explains the usage of config_string in vehicle_prop_config. Property with
+ * this annotation is expected to have additional information in config_string
+ * for that property to work.
+ * @range_start, @range_end : define range of specific property values.
+ */
+//===== Vehicle Information ====
+
+/**
+ * Invalid property value used for argument where invalid property gives different result.
+ * @range_start
+ */
+#define VEHICLE_PROPERTY_INVALID (0x0)
+
+/**
+ * VIN of vehicle
+ * @value_type VEHICLE_VALUE_TYPE_STRING
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_STATIC
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member info_vin
+ */
+#define VEHICLE_PROPERTY_INFO_VIN (0x00000100)
+
+/**
+ * Maker name of vehicle
+ * @value_type VEHICLE_VALUE_TYPE_STRING
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_STATIC
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member info_make
+ */
+#define VEHICLE_PROPERTY_INFO_MAKE (0x00000101)
+
+/**
+ * Model of vehicle
+ * @value_type VEHICLE_VALUE_TYPE_STRING
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_STATIC
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member info_model
+ */
+#define VEHICLE_PROPERTY_INFO_MODEL (0x00000102)
+
+/**
+ * Model year of vehicle.
+ * @value_type VEHICLE_VALUE_TYPE_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_STATIC
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member info_model_year
+ * @unit VEHICLE_UNIT_TYPE_YEAR
+ */
+#define VEHICLE_PROPERTY_INFO_MODEL_YEAR (0x00000103)
+
+/**
+ * Fuel capacity of the vehicle
+ * @value_type VEHICLE_VALUE_TYPE_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_STATIC
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member info_fuel_capacity
+ * @unit VEHICLE_UNIT_TYPE_VEHICLE_UNIT_TYPE_MILLILITER
+ */
+#define VEHICLE_PROPERTY_INFO_FUEL_CAPACITY (0x00000104)
+
+
+//==== Vehicle Performance Sensors ====
+
+/**
+ * Current odometer value of the vehicle
+ * @value_type VEHICLE_VALUE_TYPE_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member odometer
+ * @unit VEHICLE_UNIT_TYPE_KILOMETER
+ */
+#define VEHICLE_PROPERTY_PERF_ODOMETER (0x00000204)
+
+/**
+ * Speed of the vehicle
+ * @value_type VEHICLE_VALUE_TYPE_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member vehicle_speed
+ * @unit VEHICLE_UNIT_TYPE_METER_PER_SEC
+ */
+#define VEHICLE_PROPERTY_PERF_VEHICLE_SPEED (0x00000207)
+
+
+//==== Engine Sensors ====
+
+/**
+ * Temperature of engine coolant
+ * @value_type VEHICLE_VALUE_TYPE_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member engine_coolant_temperature
+ * @unit VEHICLE_UNIT_TYPE_CELCIUS
+ */
+#define VEHICLE_PROPERTY_ENGINE_COOLANT_TEMP (0x00000301)
+
+/**
+ * Temperature of engine oil
+ * @value_type VEHICLE_VALUE_TYPE_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member engine_oil_temperature
+ * @unit VEHICLE_UNIT_TYPE_CELCIUS
+ */
+#define VEHICLE_PROPERTY_ENGINE_OIL_TEMP (0x00000304)
+/**
+ * Engine rpm
+ * @value_type VEHICLE_VALUE_TYPE_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member engine_rpm
+ * @unit VEHICLE_UNIT_TYPE_RPM
+ */
+#define VEHICLE_PROPERTY_ENGINE_RPM (0x00000305)
+
+//==== Event Sensors ====
+
+/**
+ * Currently selected gear
+ * @value_type VEHICLE_VALUE_TYPE_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member gear_selection
+ * @data_enum vehicle_gear
+ */
+#define VEHICLE_PROPERTY_GEAR_SELECTION (0x00000400)
+
+/**
+ * Current gear. In non-manual case, selected gear does not necessarily match the current gear
+ * @value_type VEHICLE_VALUE_TYPE_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member gear_current_gear
+ * @data_enum vehicle_gear
+ */
+#define VEHICLE_PROPERTY_CURRENT_GEAR (0x00000401)
+
+/**
+ * Parking brake state.
+ * @value_type VEHICLE_VALUE_TYPE_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member parking_brake
+ * @data_enum vehicle_boolean
+ */
+#define VEHICLE_PROPERTY_PARKING_BRAKE_ON (0x00000402)
+
+/**
+ * Driving status policy.
+ * @value_type VEHICLE_VALUE_TYPE_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member driving_status
+ * @data_enum vehicle_driving_status
+ */
+#define VEHICLE_PROPERTY_DRIVING_STATUS (0x00000404)
+
+/**
+ * Warning for fuel low level.
+ * @value_type VEHICLE_VALUE_TYPE_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member is_fuel_level_low
+ * @data_enum vehicle_boolean
+ */
+#define VEHICLE_PROPERTY_FUEL_LEVEL_LOW (0x00000405)
+
+/**
+ * Night mode or not.
+ * @value_type VEHICLE_VALUE_TYPE_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member night_mode
+ * @data_enum vehicle_boolean
+ */
+#define VEHICLE_PROPERTY_NIGHT_MODE (0x00000407)
+
+
+
+ //==== HVAC Properties ====
+
+/**
+ * Fan speed setting
+ * @value_type VEHICLE_VALUE_TYPE_ZONED_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags Supported zones
+ * @data_member hvac.fan_speed
+ * @data_enum TODO
+ */
+#define VEHICLE_PROPERTY_HVAC_FAN_SPEED (0x00000500)
+
+/**
+ * Fan direction setting
+ * @value_type VEHICLE_VALUE_TYPE_ZONED_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags Supported zones
+ * @data_member hvac.fan_direction
+ * @data_enum TODO
+ */
+#define VEHICLE_PROPERTY_HVAC_FAN_DIRECTION (0x00000501)
+
+/*
+ * Bit flags for fan direction
+ */
+enum vehicle_hvac_fan_direction_flags {
+ VEHICLE_HVAC_FAN_DIRECTION_FACE_FLAG = 0x1,
+ VEHICLE_HVAC_FAN_DIRECTION_FLOOR_FLAG = 0x2,
+ VEHICLE_HVAC_FAN_DIRECTION_FACE_AND_FLOOR_FLAG = 0x3
+};
+
+/**
+ * HVAC current temperature.
+ * @value_type VEHICLE_VALUE_TYPE_ZONED_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags Supported zones
+ * @data_member hvac.temperature_current
+ */
+#define VEHICLE_PROPERTY_HVAC_TEMPERATURE_CURRENT (0x00000502)
+
+/**
+ * HVAC, target temperature set.
+ * @value_type VEHICLE_VALUE_TYPE_ZONED_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @config_flags Supported zones
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @data_member hvac.temperature_set
+ */
+#define VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET (0x00000503)
+
+/**
+ * On/off defrost
+ * @value_type VEHICLE_VALUE_TYPE_ZONED_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags Supported zones
+ * @data_member hvac.defrost_on
+ */
+#define VEHICLE_PROPERTY_HVAC_DEFROSTER (0x00000504)
+
+/**
+ * On/off AC
+ * @value_type VEHICLE_VALUE_TYPE_ZONED_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags Supported zones
+ * @data_member hvac.ac_on
+ */
+#define VEHICLE_PROPERTY_HVAC_AC_ON (0x00000505)
+
+/**
+ * On/off max AC
+ * @value_type VEHICLE_VALUE_TYPE_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @data_member hvac.max_ac_on
+ */
+#define VEHICLE_PROPERTY_HVAC_MAX_AC_ON (0x00000506)
+
+/**
+ * On/off max defrost
+ * @value_type VEHICLE_VALUE_TYPE_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @data_member hvac.max_defrost_on
+ */
+#define VEHICLE_PROPERTY_HVAC_MAX_DEFROST_ON (0x00000507)
+
+/**
+ * On/off re-circulation
+ * @value_type VEHICLE_VALUE_TYPE_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @data_member hvac.max_recirc_on
+ */
+#define VEHICLE_PROPERTY_HVAC_RECIRC_ON (0x00000508)
+
+/**
+ * On/off dual
+ * @value_type VEHICLE_VALUE_TYPE_BOOLEAN
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @data_member hvac.dual_on
+ */
+#define VEHICLE_PROPERTY_HVAC_DUAL_ON (0x00000509)
+
+/**
+ * Outside temperature
+ * @value_type VEHICLE_VALUE_TYPE_FLOAT
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE|VEHICLE_PROP_CHANGE_MODE_CONTINUOUS
+ * @access VEHICLE_PROP_ACCESS_READ
+ * @data_member outside_temperature
+ * @unit VEHICLE_UNIT_TYPE_CELCIUS
+ */
+#define VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP (0x00000703)
+
+
+/*
+ * Radio features.
+ */
+/**
+ * Radio presets stored on the Car radio module. The data type used is int32
+ * array with the following fields:
+ * <ul>
+ * <li> int32_array[0]: Preset number </li>
+ * <li> int32_array[1]: Band type (see #RADIO_BAND_FM in
+ * system/core/include/system/radio.h).
+ * <li> int32_array[2]: Channel number </li>
+ * <li> int32_array[3]: Sub channel number </li>
+ * </ul>
+ *
+ * NOTE: When getting a current preset config ONLY set preset number (i.e.
+ * int32_array[0]). For setting a preset other fields are required.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32_VEC4
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags Number of presets supported
+ * @data_member int32_array
+ */
+#define VEHICLE_PROPERTY_RADIO_PRESET (0x0000801)
+
+/**
+ * Constants relevant to radio.
+ */
+enum vehicle_radio_consts {
+ /** Minimum value for the radio preset */
+ VEHICLE_RADIO_PRESET_MIN_VALUE = 1,
+};
+
+/**
+ * Represents audio focus state of Android side. Note that car's audio module will own audio
+ * focus and grant audio focus to Android side when requested by Android side. The focus has both
+ * per stream characteristics and global characteristics.
+ *
+ * Focus request (get of this property) will take the following form in int32_vec4:
+ * int32_array[0]: vehicle_audio_focus_request type
+ * int32_array[1]: bit flags of streams requested by this focus request. There can be up to
+ * 32 streams.
+ * int32_array[2]: External focus state flags. For request, only flag like
+ * VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG can be used.
+ * This is for case like radio where android side app still needs to hold focus
+ * but playback is done outside Android.
+ * Note that each focus request can request multiple streams that is expected to be used for
+ * the current request. But focus request itself is global behavior as GAIN or GAIN_TRANSIENT
+ * expects all sounds played by car's audio module to stop. Note that stream already allocated to
+ * android before this focus request should not be affected by focus request.
+ *
+ * Focus response (set and subscription callback for this property) will take the following form:
+ * int32_array[0]: vehicle_audio_focus_state type
+ * int32_array[1]: bit flags of streams allowed.
+ * int32_array[2]: External focus state: bit flags of currently active audio focus in car
+ * side (outside Android). Active audio focus does not necessarily mean currently
+ * playing, but represents the state of having focus or waiting for focus
+ * (pause state).
+ * One or combination of flags from vehicle_audio_ext_focus_flag.
+ * 0 means no active audio focus holder outside Android.
+ * The state will have following values for each vehicle_audio_focus_state_type:
+ * GAIN: 0 or VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY when radio is active in
+ * Android side.
+ * GAIN_TRANSIENT: 0. Can be VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT or
+ * VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT if android side has requested
+ * GAIN_TRANSIENT_MAY_DUCK and car side is ducking.
+ * LOSS: 0 when no focus is audio is active in car side.
+ * VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT when car side is playing something
+ * permanent.
+ * LOSS_TRANSIENT: always should be VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT
+ *
+ * If car does not support VEHICLE_PROPERTY_AUDIO_FOCUS, focus is assumed to be granted always.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32_VEC3
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @data_member int32_array
+ */
+#define VEHICLE_PROPERTY_AUDIO_FOCUS (0x00000900)
+
+enum vehicle_audio_focus_request {
+ VEHICLE_AUDIO_FOCUS_REQUEST_GAIN = 0x1,
+ VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT = 0x2,
+ VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3,
+ VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE = 0x4,
+};
+
+enum vehicle_audio_focus_state {
+ /**
+ * Android side has permanent focus and can play allowed streams.
+ */
+ VEHICLE_AUDIO_FOCUS_STATE_GAIN = 0x1,
+ /**
+ * Android side has transient focus and can play allowed streams.
+ */
+ VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT = 0x2,
+ /**
+ * Car audio module is playing guidance kind of sound outside Android. Android side can
+ * still play through allowed streams with ducking.
+ */
+ VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3,
+ /**
+ * Car audio module is playing transient sound outside Android. Android side should stop
+ * playing any sounds.
+ */
+ VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT = 0x4,
+ /**
+ * Android side has lost focus and cannot play any sound.
+ */
+ VEHICLE_AUDIO_FOCUS_STATE_LOSS = 0x5,
+ /**
+ * car audio module is playing safety critical sound, and Android side cannot request focus
+ * until the current state is finished. car audio module should restore it to the previous
+ * state when it can allow Android to play.
+ */
+ VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE = 0x6,
+};
+
+/**
+ * Flags to represent multiple streams by combining these.
+ */
+enum vehicle_audio_stream_flag {
+ VEHICLE_AUDIO_STREAM_STREAM0_FLAG = (0x1<<0),
+ VEHICLE_AUDIO_STREAM_STREAM1_FLAG = (0x1<<1),
+ VEHICLE_AUDIO_STREAM_STREAM2_FLAG = (0x1<<2),
+};
+
+/**
+ * Represents stream number (always 0 to N -1 where N is max number of streams).
+ * Can be used for audio related property expecting one stream.
+ */
+enum vehicle_audio_stream {
+ VEHICLE_AUDIO_STREAM0 = 0,
+ VEHICLE_AUDIO_STREAM1 = 1,
+};
+
+/**
+ * Flag to represent external focus state (outside Android).
+ */
+enum vehicle_audio_ext_focus_flag {
+ /**
+ * No external focus holder.
+ */
+ VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG = 0x0,
+ /**
+ * Car side (outside Android) has component holding GAIN kind of focus state.
+ */
+ VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG = 0x1,
+ /**
+ * Car side (outside Android) has component holding GAIN_TRANSIENT kind of focus state.
+ */
+ VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT_FLAG = 0x2,
+ /**
+ * Car side is expected to play something while focus is held by Android side. One example
+ * can be radio attached in car side. But Android's radio app still should have focus,
+ * and Android side should be in GAIN state, but media stream will not be allocated to Android
+ * side and car side can play radio any time while this flag is active.
+ */
+ VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG = 0x4,
+};
+
+/**
+ * Index in int32_array for VEHICLE_PROPERTY_AUDIO_FOCUS property.
+ */
+enum vehicle_audio_focus_index {
+ VEHICLE_AUDIO_FOCUS_INDEX_FOCUS = 0,
+ VEHICLE_AUDIO_FOCUS_INDEX_STREAMS = 1,
+ VEHICLE_AUDIO_FOCUS_INDEX_EXTERNAL_FOCUS_STATE = 2,
+};
+
+/**
+ * Property to control audio volume of each audio context.
+ *
+ * Data type looks like:
+ * int32_array[0] : stream context as defined in vehicle_audio_context_flag.
+ * int32_array[1] : volume level, valid range is 0 to int32_max_value defined in config.
+ * 0 will be mute state. int32_min_value in config should be always 0.
+ * int32_array[2] : One of vehicle_audio_volume_state.
+ *
+ * This property requires per stream based get. HAL implementation should check stream number
+ * in get call to return the right volume.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32_VEC3
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags all audio contexts supported.
+ * @data_member int32_array
+ */
+#define VEHICLE_PROPERTY_AUDIO_VOLUME (0x00000901)
+
+/**
+ * enum to represent audio volume state.
+ */
+enum vehicle_audio_volume_state {
+ VEHICLE_AUDIO_VOLUME_STATE_OK = 0,
+ /**
+ * Audio volume has reached volume limit set in VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT
+ * and user's request to increase volume further is not allowed.
+ */
+ VEHICLE_AUDIO_VOLUME_STATE_LIMIT_REACHED = 1,
+};
+
+/**
+ * Index in int32_array for VEHICLE_PROPERTY_AUDIO_VOLUME property.
+ */
+enum vehicle_audio_volume_index {
+ VEHICLE_AUDIO_VOLUME_INDEX_STREAM = 0,
+ VEHICLE_AUDIO_VOLUME_INDEX_VOLUME = 1,
+ VEHICLE_AUDIO_VOLUME_INDEX_STATE = 2,
+};
+
+/**
+ * Property for handling volume limit set by user. This limits maximum volume that can be set
+ * per each context.
+ * int32_array[0] : stream context as defined in vehicle_audio_context_flag.
+ * int32_array[1] : maximum volume set to the stream. If there is no restriction, this value
+ * will be bigger than VEHICLE_PROPERTY_AUDIO_VOLUME's max value.
+ *
+ * If car does not support this feature, this property should not be populated by HAL.
+ * This property requires per stream based get. HAL implementation should check stream number
+ * in get call to return the right volume.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32_VEC2
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags all audio contexts supported.
+ * @data_member int32_array
+ */
+#define VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT (0x00000902)
+
+/**
+ * Index in int32_array for VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT property.
+ */
+enum vehicle_audio_volume_limit_index {
+ VEHICLE_AUDIO_VOLUME_LIMIT_INDEX_STREAM = 0,
+ VEHICLE_AUDIO_VOLUME_LIMIT_INDEX_MAX_VOLUME = 1,
+};
+
+/**
+ * Property to share audio routing policy of android side. This property is set at the beginning
+ * to pass audio policy in android side down to vehicle HAL and car audio module.
+ * This can be used as a hint to adjust audio policy or other policy decision.
+ *
+ * int32_array[0] : audio stream where the audio for the application context will be routed
+ * by default. Note that this is the default setting from system, but each app
+ * may still use different audio stream for whatever reason.
+ * int32_array[1] : All audio contexts that will be sent through the physical stream. Flag
+ * is defined in vehicle_audio_context_flag.
+
+ * Setting of this property will be done for all available physical streams based on audio H/W
+ * variant information acquired from VEHICLE_PROPERTY_AUDIO_HW_VARIANT property.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32_VEC2
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_WRITE
+ * @data_member int32_array
+ */
+#define VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY (0x00000903)
+
+/**
+ * Index in int32_array for VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY property.
+ */
+enum vehicle_audio_routing_policy_index {
+ VEHICLE_AUDIO_ROUTING_POLICY_INDEX_STREAM = 0,
+ VEHICLE_AUDIO_ROUTING_POLICY_INDEX_CONTEXTS = 1,
+};
+
+/**
+* Property to return audio H/W variant type used in this car. This allows android side to
+* support different audio policy based on H/W variant used. Note that other components like
+* CarService may need overlay update to support additional variants. If this property does not
+* exist, default audio policy will be used.
+*
+* @value_type VEHICLE_VALUE_TYPE_INT32
+* @change_mode VEHICLE_PROP_CHANGE_MODE_STATIC
+* @access VEHICLE_PROP_ACCESS_READ
+* @config_flags Additional info on audio H/W. Should use vehicle_audio_hw_variant_config_flag for
+* this.
+* @data_member int32_value
+*/
+#define VEHICLE_PROPERTY_AUDIO_HW_VARIANT (0x00000904)
+
+/**
+ * Flag to be used in vehicle_prop_config.config_flags for VEHICLE_PROPERTY_AUDIO_HW_VARIANT.
+ */
+enum vehicle_audio_hw_variant_config_flag {
+ /**
+ * This is a flag to disable the default behavior of not sending focus request for radio module.
+ * By default, when radio app request audio focus, that focus request is filtered out and
+ * is not sent to car audio module as radio is supposed to be played by car radio module and
+ * android side should have have audio focus for media stream.
+ * But in some H/W, radio may be directly played from android side, and in that case,
+ * android side should take focus for media stream. This flag should be enabled in such case.
+ */
+ VEHICLE_AUDIO_HW_VARIANT_FLAG_PASS_RADIO_AUDIO_FOCUS_FLAG = 0x1,
+};
+
+/**
+ * Property to share currently active audio context in android side.
+ * This can be used as a hint to adjust audio policy or other policy decision. Note that there
+ * can be multiple context active at the same time.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_WRITE
+ * @data_member int32
+ */
+#define VEHICLE_PROPERTY_AUDIO_CONTEXT (0x00000905)
+/**
+ * Flags to tell the current audio context.
+ */
+enum vehicle_audio_context_flag {
+ /** Music playback is currently active. */
+ VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG = 0x1,
+ /** Navigation is currently running. */
+ VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG = 0x2,
+ /** Voice command session is currently running. */
+ VEHICLE_AUDIO_CONTEXT_VOICE_COMMAND_FLAG = 0x4,
+ /** Voice call is currently active. */
+ VEHICLE_AUDIO_CONTEXT_CALL_FLAG = 0x8,
+ /** Alarm is active. This may be only used in VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY. */
+ VEHICLE_AUDIO_CONTEXT_ALARM_FLAG = 0x10,
+ /**
+ * Notification sound is active. This may be only used in VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY.
+ */
+ VEHICLE_AUDIO_CONTEXT_NOTIFICATION_FLAG = 0x20,
+ /**
+ * Context unknown. Only used for VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY to represent default
+ * stream for unknown contents.
+ */
+ VEHICLE_AUDIO_CONTEXT_UNKNOWN_FLAG = 0x40,
+ /** Safety alert / warning is played. */
+ VEHICLE_AUDIO_CONTEXT_SAFETY_ALERT_FLAG = 0x80,
+ /** CD / DVD kind of audio is played */
+ VEHICLE_AUDIO_CONTEXT_CD_ROM = 0x100,
+ /** Aux audio input is played */
+ VEHICLE_AUDIO_CONTEXT_AUX_AUDIO = 0x200,
+};
+
+/**
+ * Property to control power state of application processor.
+ *
+ * It is assumed that AP's power state is controller by separate power controller.
+ *
+ * For configuration information, vehicle_prop_config.config_flags can have bit flag combining
+ * values in vehicle_ap_power_state_config_type.
+ *
+ * For get / notification, data type looks like this:
+ * int32_array[0] : vehicle_ap_power_state_type
+ * int32_array[1] : additional parameter relevant for each state. should be 0 if not used.
+ * For set, data type looks like this:
+ * int32_array[0] : vehicle_ap_power_state_set_type
+ * int32_array[1] : additional parameter relevant for each request. should be 0 if not used.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32_VEC2
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ * @config_flags Additional info on power state. Should use vehicle_ap_power_state_config_flag.
+ * @data_member int32_array
+ */
+#define VEHICLE_PROPERTY_AP_POWER_STATE (0x00000A00)
+
+enum vehicle_ap_power_state_config_flag {
+ /**
+ * AP can enter deep sleep state. If not set, AP will always shutdown from
+ * VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE power state.
+ */
+ VEHICLE_AP_POWER_STATE_CONFIG_ENABLE_DEEP_SLEEP_FLAG = 0x1,
+
+ /**
+ * The power controller can power on AP from off state after timeout specified in
+ * VEHICLE_AP_POWER_SET_SHUTDOWN_READY message.
+ */
+ VEHICLE_AP_POWER_STATE_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2,
+};
+
+enum vehicle_ap_power_state {
+ /** vehicle HAL will never publish this state to AP */
+ VEHICLE_AP_POWER_STATE_OFF = 0,
+ /** vehicle HAL will never publish this state to AP */
+ VEHICLE_AP_POWER_STATE_DEEP_SLEEP = 1,
+ /** AP is on but display should be off. */
+ VEHICLE_AP_POWER_STATE_ON_DISP_OFF = 2,
+ /** AP is on with display on. This state allows full user interaction. */
+ VEHICLE_AP_POWER_STATE_ON_FULL = 3,
+ /**
+ * The power controller has requested AP to shutdown. AP can either enter sleep state or start
+ * full shutdown. AP can also request postponing shutdown by sending
+ * VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE message. The power controller should change power
+ * state to this state to shutdown system.
+ *
+ * int32_array[1] : one of enum_vehicle_ap_power_state_shutdown_param_type
+ */
+ VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE = 4,
+};
+
+enum vehicle_ap_power_state_shutdown_param {
+ /** AP should shutdown immediately. Postponing is not allowed. */
+ VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_IMMEDIATELY = 1,
+ /** AP can enter deep sleep instead of shutting down completely. */
+ VEHICLE_AP_POWER_SHUTDOWN_PARAM_CAN_SLEEP = 2,
+ /** AP can only shutdown with postponing allowed. */
+ VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_ONLY = 3,
+};
+
+enum vehicle_ap_power_set_state {
+ /**
+ * AP has finished boot up, and can start shutdown if requested by power controller.
+ */
+ VEHICLE_AP_POWER_SET_BOOT_COMPLETE = 0x1,
+ /**
+ * AP is entering deep sleep state. How this state is implemented may vary depending on
+ * each H/W, but AP's power should be kept in this state.
+ */
+ VEHICLE_AP_POWER_SET_DEEP_SLEEP_ENTRY = 0x2,
+ /**
+ * AP is exiting from deep sleep state, and is in VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE state.
+ * The power controller may change state to other ON states based on the current state.
+ */
+ VEHICLE_AP_POWER_SET_DEEP_SLEEP_EXIT = 0x3,
+ /**
+ * int32_array[1]: Time to postpone shutdown in ms. Maximum value can be 5000 ms.
+ * If AP needs more time, it will send another POSTPONE message before
+ * the previous one expires.
+ */
+ VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE = 0x4,
+ /**
+ * AP is starting shutting down. When system completes shutdown, everything will stop in AP
+ * as kernel will stop all other contexts. It is responsibility of vehicle HAL or lower level
+ * to synchronize that state with external power controller. As an example, some kind of ping
+ * with timeout in power controller can be a solution.
+ *
+ * int32_array[1]: Time to turn on AP in secs. Power controller may turn on AP after specified
+ * time so that AP can run tasks like update. If it is set to 0, there is no
+ * wake up, and power controller may not necessarily support wake-up.
+ * If power controller turns on AP due to timer, it should start with
+ * VEHICLE_AP_POWER_STATE_ON_DISP_OFF state, and after receiving
+ * VEHICLE_AP_POWER_SET_BOOT_COMPLETE, it shall do state transition to
+ * VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE.
+ */
+ VEHICLE_AP_POWER_SET_SHUTDOWN_START = 0x5,
+ /**
+ * User has requested to turn off headunit's display, which is detected in android side.
+ * The power controller may change the power state to VEHICLE_AP_POWER_STATE_ON_DISP_OFF.
+ */
+ VEHICLE_AP_POWER_SET_DISPLAY_OFF = 0x6,
+ /**
+ * User has requested to turn on headunit's display, most probably from power key input which
+ * is attached to headunit. The power controller may change the power state to
+ * VEHICLE_AP_POWER_STATE_ON_FULL.
+ */
+ VEHICLE_AP_POWER_SET_DISPLAY_ON = 0x7,
+};
+
+/**
+ * Property to represent brightness of the display. Some cars have single control for
+ * the brightness of all displays and this property is to share change in that control.
+ *
+ * If this is writable, android side can set this value when user changes display brightness
+ * from Settings. If this is read only, user may still change display brightness from Settings,
+ * but that will not be reflected to other displays.
+ *
+ * @value_type VEHICLE_VALUE_TYPE_INT32
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ|VEHICLE_PROP_ACCESS_READ_WRITE
+ * @data_member int32
+ */
+#define VEHICLE_PROPERTY_DISPLAY_BRIGHTNESS (0x00000A01)
+
+
+/**
+ * Index in int32_array for VEHICLE_PROPERTY_AP_POWER_STATE property.
+ */
+enum vehicle_ap_power_state_index {
+ VEHICLE_AP_POWER_STATE_INDEX_STATE = 0,
+ VEHICLE_AP_POWER_STATE_INDEX_ADDITIONAL = 1,
+};
+
+/**
+* Property to report bootup reason for the current power on. This is a static property that will
+* not change for the whole duration until power off. For example, even if user presses power on
+* button after automatic power on with door unlock, bootup reason should stay with
+* VEHICLE_AP_POWER_BOOTUP_REASON_USER_UNLOCK.
+*
+* int32_value should be vehicle_ap_power_bootup_reason.
+*
+* @value_type VEHICLE_VALUE_TYPE_INT32
+* @change_mode VEHICLE_PROP_CHANGE_MODE_STATIC
+* @access VEHICLE_PROP_ACCESS_READ
+* @data_member int32_value
+*/
+#define VEHICLE_PROPERTY_AP_POWER_BOOTUP_REASON (0x00000A02)
+
+/**
+ * Enum to represent bootup reason.
+ */
+enum vehicle_ap_power_bootup_reason {
+ /**
+ * Power on due to user's pressing of power key or rotating of ignition switch.
+ */
+ VEHICLE_AP_POWER_BOOTUP_REASON_USER_POWER_ON = 0,
+ /**
+ * Automatic power on triggered by door unlock or any other kind of automatic user detection.
+ */
+ VEHICLE_AP_POWER_BOOTUP_REASON_USER_UNLOCK = 1,
+ /**
+ * Automatic power on triggered by timer. This only happens when AP has asked wake-up after
+ * certain time through time specified in VEHICLE_AP_POWER_SET_SHUTDOWN_START.
+ */
+ VEHICLE_AP_POWER_BOOTUP_REASON_TIMER = 2,
+};
+
+/**
+ * H/W specific, non-standard property can be added as necessary. Such property should use
+ * property number in range of [VEHICLE_PROPERTY_CUSTOM_START, VEHICLE_PROPERTY_CUSTOM_END].
+ * Definition of property in this range is completely up to each HAL implementation.
+ * For such property, it is recommended to fill vehicle_prop_config.config_string with some
+ * additional information to help debugging. For example, company XYZ's custom extension may
+ * include config_string of "com.XYZ.some_further_details".
+ * @range_start
+ */
+#define VEHICLE_PROPERTY_CUSTOM_START (0x70000000)
+/** @range_end */
+#define VEHICLE_PROPERTY_CUSTOM_END (0x73ffffff)
+
+/**
+ * Property range allocated for system's internal usage like testing. HAL should never declare
+ * property in this range.
+ * @range_start
+ */
+#define VEHICLE_PROPERTY_INTERNAL_START (0x74000000)
+/**
+ * @range_end
+ */
+#define VEHICLE_PROPERTY_INTERNAL_END (0x74ffffff)
+
+/**
+ * Value types for various properties.
+ */
+enum vehicle_value_type {
+ VEHICLE_VALUE_TYPE_SHOUD_NOT_USE = 0x00, // value_type should never set to 0.
+ VEHICLE_VALUE_TYPE_STRING = 0x01,
+ VEHICLE_VALUE_TYPE_BYTES = 0x02,
+ VEHICLE_VALUE_TYPE_BOOLEAN = 0x03,
+ VEHICLE_VALUE_TYPE_ZONED_BOOLEAN = 0x04,
+ VEHICLE_VALUE_TYPE_INT64 = 0x05,
+ VEHICLE_VALUE_TYPE_FLOAT = 0x10,
+ VEHICLE_VALUE_TYPE_FLOAT_VEC2 = 0x11,
+ VEHICLE_VALUE_TYPE_FLOAT_VEC3 = 0x12,
+ VEHICLE_VALUE_TYPE_FLOAT_VEC4 = 0x13,
+ VEHICLE_VALUE_TYPE_INT32 = 0x20,
+ VEHICLE_VALUE_TYPE_INT32_VEC2 = 0x21,
+ VEHICLE_VALUE_TYPE_INT32_VEC3 = 0x22,
+ VEHICLE_VALUE_TYPE_INT32_VEC4 = 0x23,
+ VEHICLE_VALUE_TYPE_ZONED_FLOAT = 0x30,
+ VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC2 = 0x31,
+ VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC3 = 0x32,
+ VEHICLE_VALUE_TYPE_ZONED_INT32 = 0x40,
+ VEHICLE_VALUE_TYPE_ZONED_INT32_VEC2 = 0x41,
+ VEHICLE_VALUE_TYPE_ZONED_INT32_VEC3 = 0x42,
+};
+
+/**
+ * Units used for int or float type with no attached enum types.
+ */
+enum vehicle_unit_type {
+ VEHICLE_UNIT_TYPE_SHOULD_NOT_USE = 0x00000000,
+ // speed related items
+ VEHICLE_UNIT_TYPE_METER_PER_SEC = 0x00000001,
+ VEHICLE_UNIT_TYPE_RPM = 0x00000002,
+ VEHICLE_UNIT_TYPE_HZ = 0x00000003,
+ // kind of ratio
+ VEHICLE_UNIT_TYPE_PERCENTILE = 0x00000010,
+ // length
+ VEHICLE_UNIT_TYPE_MILLIMETER = 0x00000020,
+ VEHICLE_UNIT_TYPE_METER = 0x00000021,
+ VEHICLE_UNIT_TYPE_KILOMETER = 0x00000023,
+ // temperature
+ VEHICLE_UNIT_TYPE_CELCIUS = 0x00000030,
+ // volume
+ VEHICLE_UNIT_TYPE_MILLILITER = 0x00000040,
+ // time
+ VEHICLE_UNIT_TYPE_NANO_SECS = 0x00000050,
+ VEHICLE_UNOT_TYPE_SECS = 0x00000053,
+ VEHICLE_UNIT_TYPE_YEAR = 0x00000059,
+};
+
+/**
+ * Error code used in HAL implemnentation. Follows utils/Errors.h
+ */
+enum vehicle_error_code {
+ VEHICLE_NO_ERROR = 0x0,
+ VEHICLE_ERROR_UNKNOWN = (-2147483647 - 1), // INT32_MIN value
+ VEHICLE_ERROR_NO_MEMORY = -12, //ENOMEM
+ VEHICLE_ERROR_INVALID_OPERATION = -38, //ENOSYS
+ VEHICLE_ERROR_BAD_VALUE = -22, //EINVAL
+ VEHICLE_ERROR_BAD_TYPE = (VEHICLE_ERROR_UNKNOWN + 1),
+ VEHICLE_ERROR_NAME_NOT_FOUND = -2, //ENOENT
+ VEHICLE_ERROR_PERMISSION_DENIED = -1, //EPERM
+ VEHICLE_ERROR_NO_INIT = -19, //ENODEV
+ VEHICLE_ERROR_ALREADY_EXISTS = -17, //EEXIST
+ VEHICLE_ERROR_DEAD_OBJECT = -32, //EPIPE
+ VEHICLE_ERROR_FAILED_TRANSACTION = (VEHICLE_ERROR_UNKNOWN + 2),
+ VEHICLE_ERROR_BAD_INDEX = -75, //EOVERFLOW
+ VEHICLE_ERROR_NOT_ENOUGH_DATA = -61, //ENODATA
+ VEHICLE_ERROR_WOULD_BLOCK = -11, //EWOULDBLOCK
+ VEHICLE_ERROR_TIMED_OUT = -110, //ETIMEDOUT
+ VEHICLE_ERROR_UNKNOWN_TRANSACTION = -74, //EBADMSG
+ VEHICLE_FDS_NOT_ALLOWED = (VEHICLE_ERROR_UNKNOWN + 7),
+};
+
+/**
+ * This describes how value of property can change.
+ */
+enum vehicle_prop_change_mode {
+ /**
+ * Property of this type will *never* change. This property will not support subscription, but
+ * will support get
+ */
+ VEHICLE_PROP_CHANGE_MODE_STATIC = 0x00,
+ /**
+ * Property of this type will be reported when there is a change. get should return the
+ * current value.
+ */
+ VEHICLE_PROP_CHANGE_MODE_ON_CHANGE = 0x01,
+ /**
+ * Property of this type change continuously and requires fixed rate of sampling to retrieve
+ * the data.
+ */
+ VEHICLE_PROP_CHANGE_MODE_CONTINUOUS = 0x02,
+};
+
+/**
+ * Property config defines the capabilities of it. User of the API
+ * should first get the property config to understand the output from get()
+ * commands and also to ensure that set() or events commands are in sync with
+ * the expected output.
+ */
+enum vehicle_prop_access {
+ VEHICLE_PROP_ACCESS_READ = 0x01,
+ VEHICLE_PROP_ACCESS_WRITE = 0x02,
+ VEHICLE_PROP_ACCESS_READ_WRITE = 0x03
+};
+
+/**
+ * These permissions define how the OEMs want to distribute their information and security they
+ * want to apply. On top of these restrictions, android will have additional
+ * 'app-level' permissions that the apps will need to ask the user before the apps have the
+ * information.
+ * This information should be kept in vehicle_prop_config.permission_model.
+ */
+enum vehicle_permission_model {
+ /**
+ * No special restriction, but each property can still require specific android app-level
+ * permission.
+ */
+ VEHICLE_PERMISSION_NO_RESTRICTION = 0,
+ /** Signature only. Only APKs signed with OEM keys are allowed. */
+ VEHICLE_PERMISSION_OEM_ONLY = 0x1,
+ /** System only. APKs built-in to system can access the property. */
+ VEHICLE_PERMISSION_SYSTEM_APP_ONLY = 0x2,
+ /** Equivalent to “system|signature” */
+ VEHICLE_PERMISSION_OEM_OR_SYSTEM_APP = 0x3
+};
+
+/**
+ * Car states.
+ *
+ * The driving states determine what features of the UI will be accessible.
+ */
+enum vehicle_driving_status {
+ VEHICLE_DRIVING_STATUS_UNRESTRICTED = 0x00,
+ VEHICLE_DRIVING_STATUS_NO_VIDEO = 0x01,
+ VEHICLE_DRIVING_STATUS_NO_KEYBOARD_INPUT = 0x02,
+ VEHICLE_DRIVING_STATUS_NO_VOICE_INPUT = 0x04,
+ VEHICLE_DRIVING_STATUS_NO_CONFIG = 0x08,
+ VEHICLE_DRIVING_STATUS_LIMIT_MESSAGE_LEN = 0x10
+};
+
+/**
+ * Various gears which can be selected by user and chosen in system.
+ */
+enum vehicle_gear {
+ // Gear selections present in both automatic and manual cars.
+ VEHICLE_GEAR_NEUTRAL = 0x0001,
+ VEHICLE_GEAR_REVERSE = 0x0002,
+
+ // Gear selections (mostly) present only in automatic cars.
+ VEHICLE_GEAR_PARKING = 0x0004,
+ VEHICLE_GEAR_DRIVE = 0x0008,
+ VEHICLE_GEAR_L = 0x0010,
+
+ // Other possible gear selections (maybe present in manual or automatic
+ // cars).
+ VEHICLE_GEAR_1 = 0x0010,
+ VEHICLE_GEAR_2 = 0x0020,
+ VEHICLE_GEAR_3 = 0x0040,
+ VEHICLE_GEAR_4 = 0x0080,
+ VEHICLE_GEAR_5 = 0x0100,
+ VEHICLE_GEAR_6 = 0x0200,
+ VEHICLE_GEAR_7 = 0x0400,
+ VEHICLE_GEAR_8 = 0x0800,
+ VEHICLE_GEAR_9 = 0x1000
+};
+
+
+/**
+ * Various zones in the car.
+ *
+ * Zones are used for Air Conditioning purposes and divide the car into physical
+ * area zones.
+ */
+enum vehicle_zone {
+ VEHICLE_ZONE_ROW_1_LEFT = 0x00000001,
+ VEHICLE_ZONE_ROW_1_CENTER = 0x00000002,
+ VEHICLE_ZONE_ROW_1_RIGHT = 0x00000004,
+ VEHICLE_ZONE_ROW_1_ALL = 0x00000008,
+ VEHICLE_ZONE_ROW_2_LEFT = 0x00000010,
+ VEHICLE_ZONE_ROW_2_CENTER = 0x00000020,
+ VEHICLE_ZONE_ROW_2_RIGHT = 0x00000040,
+ VEHICLE_ZONE_ROW_2_ALL = 0x00000080,
+ VEHICLE_ZONE_ROW_3_LEFT = 0x00000100,
+ VEHICLE_ZONE_ROW_3_CENTER = 0x00000200,
+ VEHICLE_ZONE_ROW_3_RIGHT = 0x00000400,
+ VEHICLE_ZONE_ROW_3_ALL = 0x00000800,
+ VEHICLE_ZONE_ROW_4_LEFT = 0x00001000,
+ VEHICLE_ZONE_ROW_4_CENTER = 0x00002000,
+ VEHICLE_ZONE_ROW_4_RIGHT = 0x00004000,
+ VEHICLE_ZONE_ROW_4_ALL = 0x00008000,
+ VEHICLE_ZONE_ALL = 0x80000000,
+};
+
+/**
+ * Various Seats in the car.
+ */
+enum vehicle_seat {
+ VEHICLE_SEAT_DRIVER_LHD = 0x0001,
+ VEHICLE_SEAT_DRIVER_RHD = 0x0002,
+ VEHICLE_SEAT_ROW_1_PASSENGER_1 = 0x0010,
+ VEHICLE_SEAT_ROW_1_PASSENGER_2 = 0x0020,
+ VEHICLE_SEAT_ROW_1_PASSENGER_3 = 0x0040,
+ VEHICLE_SEAT_ROW_2_PASSENGER_1 = 0x0100,
+ VEHICLE_SEAT_ROW_2_PASSENGER_2 = 0x0200,
+ VEHICLE_SEAT_ROW_2_PASSENGER_3 = 0x0400,
+ VEHICLE_SEAT_ROW_3_PASSENGER_1 = 0x1000,
+ VEHICLE_SEAT_ROW_3_PASSENGER_2 = 0x2000,
+ VEHICLE_SEAT_ROW_3_PASSENGER_3 = 0x4000
+};
+
+/**
+ * Various windshields/windows in the car.
+ */
+enum vehicle_window {
+ VEHICLE_WINDOW_FRONT_WINDSHIELD = 0x0001,
+ VEHICLE_WINDOW_REAR_WINDSHIELD = 0x0002,
+ VEHICLE_WINDOW_ROOF_TOP = 0x0004,
+ VEHICLE_WINDOW_ROW_1_LEFT = 0x0010,
+ VEHICLE_WINDOW_ROW_1_RIGHT = 0x0020,
+ VEHICLE_WINDOW_ROW_2_LEFT = 0x0100,
+ VEHICLE_WINDOW_ROW_2_RIGHT = 0x0200,
+ VEHICLE_WINDOW_ROW_3_LEFT = 0x1000,
+ VEHICLE_WINDOW_ROW_3_RIGHT = 0x2000,
+};
+
+enum vehicle_turn_signal {
+ VEHICLE_SIGNAL_NONE = 0x00,
+ VEHICLE_SIGNAL_RIGHT = 0x01,
+ VEHICLE_SIGNAL_LEFT = 0x02,
+ VEHICLE_SIGNAL_EMERGENCY = 0x04
+};
+
+/*
+ * Boolean type.
+ */
+enum vehicle_boolean {
+ VEHICLE_FALSE = 0x00,
+ VEHICLE_TRUE = 0x01
+};
+
+typedef int32_t vehicle_boolean_t;
+
+/**
+ * Vehicle string.
+ *
+ * Defines a UTF8 encoded sequence of bytes that should be used for string
+ * representation throughout.
+ */
+typedef struct vehicle_str {
+ uint8_t* data;
+ int32_t len;
+} vehicle_str_t;
+
+/**
+ * Vehicle byte array.
+ * This is for passing generic raw data.
+ */
+typedef vehicle_str_t vehicle_bytes_t;
+
+typedef struct vehicle_zoned_int32 {
+ union {
+ int32_t zone;
+ int32_t seat;
+ int32_t window;
+ };
+ int32_t value;
+} vehicle_zoned_int32_t;
+
+typedef struct vehicle_zoned_int32_array {
+ union {
+ int32_t zone;
+ int32_t seat;
+ int32_t window;
+ };
+ int32_t values[3];
+} vehicle_zoned_int32_array_t;
+
+typedef struct vehicle_zoned_float {
+ union {
+ int32_t zone;
+ int32_t seat;
+ int32_t window;
+ };
+ float value;
+} vehicle_zoned_float_t;
+
+typedef struct vehicle_zoned_float_array {
+ union {
+ int32_t zone;
+ int32_t seat;
+ int32_t window;
+ };
+ float values[3];
+} vehicle_zoned_float_array_t;
+
+typedef struct vehicle_zoned_boolean {
+ union {
+ int32_t zone;
+ int32_t seat;
+ int32_t window;
+ };
+ vehicle_boolean_t value;
+} vehicle_zoned_boolean_t;
+
+
+typedef struct vehicle_prop_config {
+ int32_t prop;
+
+ /**
+ * Defines if the property is read or write. Value should be one of
+ * enum vehicle_prop_access.
+ */
+ int32_t access;
+
+ /**
+ * Defines if the property is continuous or on-change. Value should be one
+ * of enum vehicle_prop_change_mode.
+ */
+ int32_t change_mode;
+
+ /**
+ * Type of data used for this property. This type is fixed per each property.
+ * Check vehicle_value_type for allowed value.
+ */
+ int32_t value_type;
+
+ /**
+ * Define necessary permission model to access the data.
+ */
+ int32_t permission_model;
+ /**
+ * Some of the properties may have associated zones (such as hvac), in these
+ * cases the config should contain an ORed value for the associated zone.
+ */
+ union {
+ /**
+ * For generic configuration information
+ */
+ int32_t config_flags;
+
+ /**
+ * The value is derived by ORing one or more of enum vehicle_zone members.
+ */
+ int32_t vehicle_zone_flags;
+ /** The value is derived by ORing one or more of enum vehicle_seat members. */
+ int32_t vehicle_seat_flags;
+ /** The value is derived by ORing one or more of enum vehicle_window members. */
+ int32_t vehicle_window_flags;
+
+ /** The number of presets that are stored by the radio module. Pass 0 if
+ * there are no presets available. The range of presets is defined to be
+ * from 1 (see VEHICLE_RADIO_PRESET_MIN_VALUE) to vehicle_radio_num_presets.
+ */
+ int32_t vehicle_radio_num_presets;
+ int32_t config_array[4];
+ };
+
+ /**
+ * Some properties may require additional information passed over this string. Most properties
+ * do not need to set this and in that case, config_string.data should be NULL and
+ * config_string.len should be 0.
+ */
+ vehicle_str_t config_string;
+
+ /**
+ * Specify minimum allowed value for the property. This is necessary for property which does
+ * not have specified enum.
+ */
+ union {
+ float float_min_value;
+ int32_t int32_min_value;
+ int64_t int64_min_value;
+ };
+
+ /**
+ * Specify maximum allowed value for the property. This is necessary for property which does
+ * not have specified enum.
+ */
+ union {
+ float float_max_value;
+ int32_t int32_max_value;
+ int64_t int64_max_value;
+ };
+
+ /**
+ * Min sample rate in Hz. Should be 0 for sensor type of VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ */
+ float min_sample_rate;
+ /**
+ * Max sample rate in Hz. Should be 0 for sensor type of VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ */
+ float max_sample_rate;
+ /**
+ * Place holder for putting HAL implementation specific data. Usage is wholly up to HAL
+ * implementation.
+ */
+ void* hal_data;
+} vehicle_prop_config_t;
+
+/**
+ * HVAC property fields.
+ *
+ * Defines various HVAC properties which are packed into vehicle_hvac_t (see
+ * below). We define these properties outside in global scope so that HAL
+ * implementation and HAL users (JNI) can typecast vehicle_hvac correctly.
+ */
+typedef vehicle_zoned_int32_t vehicle_hvac_fan_speed_t;
+
+typedef vehicle_zoned_int32_t vehicle_hvac_fan_direction_t;
+
+typedef vehicle_zoned_float_t vehicle_hvac_zone_temperature_t;
+
+//TODO Typical seat heat/cooling is done in fixed steps. Needs better definition.
+//typedef struct vehicle_hvac_seat_temperature {
+// // Value should be one of enum vehicle_seat.
+// int32_t seat;
+// float temperature;
+//} vehicle_hvac_heated_seat_temperature_t;
+
+typedef vehicle_zoned_boolean_t vehicle_hvac_defrost_on_t;
+
+typedef vehicle_zoned_boolean_t vehicle_hvac_ac_on_t;
+
+typedef vehicle_boolean_t vehicle_hvac_max_ac_on_t;
+
+typedef vehicle_boolean_t vehicle_hvac_max_defrost_on_t;
+
+typedef vehicle_boolean_t vehicle_hvac_recirc_on_t;
+
+typedef vehicle_boolean_t vehicle_hvac_dual_on_t;
+
+typedef struct vehicle_hvac {
+ /**
+ * Define one structure for each possible HVAC property.
+ * NOTES:
+ * a) Zone is defined in enum vehicle_zone.
+ * b) Fan speed is a number from (0 - 6) where 6 is the highest speed. (TODO define enum)
+ * c) Temperature is a floating point Celcius scale.
+ * d) Direction is defined in enum vehicle_fan_direction.
+ *
+ * The HAL should create #entries number of vehicle_hvac_properties and
+ * assign it to "properties" variable below.
+ */
+ union {
+ vehicle_hvac_fan_speed_t fan_speed;
+ vehicle_hvac_fan_direction_t fan_direction;
+ vehicle_hvac_ac_on_t ac_on;
+ vehicle_hvac_max_ac_on_t max_ac_on;
+ vehicle_hvac_max_defrost_on_t max_defrost_on;
+ vehicle_hvac_recirc_on_t recirc_on;
+ vehicle_hvac_dual_on_t dual_on;
+
+ vehicle_hvac_zone_temperature_t temperature_current;
+ vehicle_hvac_zone_temperature_t temperature_set;
+
+ //TODO Heated seat.
+ //vehicle_hvac_heated_seat_t heated_seat;
+
+ vehicle_hvac_defrost_on_t defrost_on;
+ };
+} vehicle_hvac_t;
+
+/*
+ * Defines how the values for various properties are represented.
+ *
+ * There are two ways to populate and access the fields:
+ * a) Using the individual fields. Use this mechanism (see
+ * info_manufacture_date, fuel_capacity fields etc).
+ * b) Using the union accessors (see uint32_value, float_value etc).
+ *
+ * To add a new field make sure that it does not exceed the total union size
+ * (defined in int_array) and it is one of the vehicle_value_type. Then add the
+ * field name with its unit to union. If the field type is not yet defined (as
+ * of this draft, we don't use int64_t) then add that type to vehicle_value_type
+ * and have an accessor (so for int64_t it will be int64_t int64_value).
+ */
+typedef union vehicle_value {
+ /** Define the max size of this structure. */
+ int32_t int32_array[4];
+ float float_array[4];
+
+ // Easy accessors for union members (HAL implementation SHOULD NOT USE these
+ // fields while populating, use the property specific fields below instead).
+ int32_t int32_value;
+ int64_t int64_value;
+ float float_value;
+ vehicle_str_t str_value;
+ vehicle_bytes_t bytes_value;
+ vehicle_boolean_t boolean_value;
+ vehicle_zoned_int32_t zoned_int32_value;
+ vehicle_zoned_int32_array_t zoned_int32_array;
+ vehicle_zoned_float_t zoned_float_value;
+ vehicle_zoned_float_array_t zoned_float_array;
+ vehicle_zoned_boolean_t zoned_boolean_value;
+
+ // Vehicle Information.
+ vehicle_str_t info_vin;
+ vehicle_str_t info_make;
+ vehicle_str_t info_model;
+ int32_t info_model_year;
+
+ // Represented in milliliters.
+ float info_fuel_capacity;
+
+ float vehicle_speed;
+ float odometer;
+
+ // Engine sensors.
+
+ // Represented in milliliters.
+ //float engine_coolant_level;
+ // Represented in celcius.
+ float engine_coolant_temperature;
+ // Represented in a percentage value.
+ //float engine_oil_level;
+ // Represented in celcius.
+ float engine_oil_temperature;
+ float engine_rpm;
+
+ // Event sensors.
+ // Value should be one of enum vehicle_gear_selection.
+ int32_t gear_selection;
+ // Value should be one of enum vehicle_gear.
+ int32_t gear_current_gear;
+ // Value should be one of enum vehicle_boolean.
+ int32_t parking_brake;
+ // If cruise_set_speed > 0 then cruise is ON otherwise cruise is OFF.
+ // Unit: meters / second (m/s).
+ //int32_t cruise_set_speed;
+ // Value should be one of enum vehicle_boolean.
+ int32_t is_fuel_level_low;
+ // Value should be one of enum vehicle_driving_status.
+ int32_t driving_status;
+ int32_t night_mode;
+ // Value should be one of emum vehicle_turn_signal.
+ int32_t turn_signals;
+ // Value should be one of enum vehicle_boolean.
+ //int32_t engine_on;
+
+ // HVAC properties.
+ vehicle_hvac_t hvac;
+
+ float outside_temperature;
+} vehicle_value_t;
+
+/*
+ * Encapsulates the property name and the associated value. It
+ * is used across various API calls to set values, get values or to register for
+ * events.
+ */
+typedef struct vehicle_prop_value {
+ /* property identifier */
+ int32_t prop;
+
+ /* value type of property for quick conversion from union to appropriate
+ * value. The value must be one of enum vehicle_value_type.
+ */
+ int32_t value_type;
+
+ /** time is elapsed nanoseconds since boot */
+ int64_t timestamp;
+
+ vehicle_value_t value;
+} vehicle_prop_value_t;
+
+/*
+ * Event callback happens whenever a variable that the API user has subscribed
+ * to needs to be reported. This may be based purely on threshold and frequency
+ * (a regular subscription, see subscribe call's arguments) or when the set()
+ * command is executed and the actual change needs to be reported.
+ *
+ * event_data is OWNED by the HAL and should be copied before the callback
+ * finishes.
+ */
+typedef int (*vehicle_event_callback_fn)(const vehicle_prop_value_t *event_data);
+
+
+/**
+ * Represent the operation where the current error has happened.
+ */
+enum vehicle_property_operation {
+ /** Generic error to this property which is not tied to any operation. */
+ VEHICLE_OPERATION_GENERIC = 0,
+ /** Error happened while handling property set. */
+ VEHICLE_OPERATION_SET = 1,
+ /** Error happened while handling property get. */
+ VEHICLE_OPERATION_GET = 2,
+ /** Error happened while handling property subscription. */
+ VEHICLE_OPERATION_SUBSCRIBE = 3,
+};
+
+/*
+ * Suggests that an error condition has occured. error_code should be one of
+ * enum vehicle_error_code.
+ *
+ * @param error_code Error code. It should be one of enum vehicle_error_code.
+ * See error code for details.
+ * @parm property Note a property where error has happened. If this is generic error, property
+ * should be VEHICLE_PROPERTY_INVALID.
+ * @param operation Represent the operation where the error has happened. Should be one of
+ * vehicle_property_operation.
+ */
+typedef int (*vehicle_error_callback_fn)(int32_t error_code, int32_t property, int32_t operation);
+
+/************************************************************************************/
+
+/*
+ * 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 vehicle_module {
+ struct hw_module_t common;
+} vehicle_module_t;
+
+
+typedef struct vehicle_hw_device {
+ struct hw_device_t common;
+
+ /**
+ * After calling open on device the user should register callbacks for event and error
+ * functions.
+ */
+ int (*init)(struct vehicle_hw_device* device,
+ vehicle_event_callback_fn event_fn, vehicle_error_callback_fn err_fn);
+ /**
+ * Before calling close the user should destroy the registered callback
+ * functions.
+ * In case the unsubscribe() call is not called on all properties before
+ * release() then release() will unsubscribe the properties itself.
+ */
+ int (*release)(struct vehicle_hw_device* device);
+
+ /**
+ * Enumerate all available properties. The list is returned in "list".
+ * @param num_properties number of properties contained in the retuned array.
+ * @return array of property configs supported by this car. Note that returned data is const
+ * and caller cannot modify it. HAL implementation should keep this memory until HAL
+ * is released to avoid copying this again.
+ */
+ vehicle_prop_config_t const *(*list_properties)(struct vehicle_hw_device* device,
+ int* num_properties);
+
+ /**
+ * Get a vehicle property value immediately. data should be allocated
+ * properly.
+ * The caller of the API OWNS the data field.
+ * Caller will set data->prop, data->value_type, and optionally zone value for zoned property.
+ * But HAL implementation needs to fill all entries properly when returning.
+ * For pointer type, HAL implementation should allocate necessary memory and caller is
+ * responsible for freeing memory for the pointer.
+ * For VEHICLE_PROP_CHANGE_MODE_STATIC type of property, get should return the same value
+ * always.
+ * For VEHICLE_PROP_CHANGE_MODE_ON_CHANGE type of property, it should return the latest value.
+ */
+ int (*get)(struct vehicle_hw_device* device, vehicle_prop_value_t *data);
+
+ /**
+ * Set a vehicle property value. data should be allocated properly and not
+ * NULL.
+ * The caller of the API OWNS the data field.
+ * timestamp of data will be ignored for set operation.
+ */
+ int (*set)(struct vehicle_hw_device* device, const vehicle_prop_value_t *data);
+
+ /**
+ * Subscribe to events.
+ * Depending on output of list_properties if the property is:
+ * a) on-change: sample_rate should be set to 0.
+ * b) supports frequency: sample_rate should be set from min_sample_rate to
+ * max_sample_rate.
+ * Subscribing to properties in-correctly may result in error callbacks and
+ * will depend on HAL implementation.
+ * @param device
+ * @param prop
+ * @param sample_rate
+ * @param zones All subscribed zones for zoned property. can be ignored for non-zoned property.
+ * 0 means all zones supported instead of no zone.
+ */
+ int (*subscribe)(struct vehicle_hw_device* device, int32_t prop, float sample_rate,
+ int32_t zones);
+
+ /** Cancel subscription on a property. */
+ int (*unsubscribe)(struct vehicle_hw_device* device, int32_t prop);
+} vehicle_hw_device_t;
+
+__END_DECLS
+
+#endif // ANDROID_VEHICLE_INTERFACE_H
diff --git a/modules/Android.mk b/modules/Android.mk
index 9f7e5f0..a77188d 100644
--- a/modules/Android.mk
+++ b/modules/Android.mk
@@ -1,4 +1,4 @@
hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time \
power usbaudio audio_remote_submix camera usbcamera consumerir sensors vibrator \
- tv_input fingerprint input
+ tv_input fingerprint input vehicle hardware_properties
include $(call all-named-subdir-makefiles,$(hardware_modules))
diff --git a/modules/gralloc/gralloc.cpp b/modules/gralloc/gralloc.cpp
index a9fbc80..e9559e9 100644
--- a/modules/gralloc/gralloc.cpp
+++ b/modules/gralloc/gralloc.cpp
@@ -196,36 +196,41 @@
/*****************************************************************************/
+inline size_t align(size_t value, size_t alignment)
+{
+ return ((value + alignment - 1) / alignment) * alignment;
+}
+
static int gralloc_alloc(alloc_device_t* dev,
- int w, int h, int format, int usage,
+ int width, int height, int format, int usage,
buffer_handle_t* pHandle, int* pStride)
{
if (!pHandle || !pStride)
return -EINVAL;
- size_t size, stride;
-
- int align = 4;
- int bpp = 0;
+ int bytesPerPixel = 0;
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
- bpp = 4;
+ bytesPerPixel = 4;
break;
case HAL_PIXEL_FORMAT_RGB_888:
- bpp = 3;
+ bytesPerPixel = 3;
break;
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RAW16:
- bpp = 2;
+ bytesPerPixel = 2;
break;
default:
return -EINVAL;
}
- size_t bpr = (w*bpp + (align-1)) & ~(align-1);
- size = bpr * h;
- stride = bpr / bpp;
+
+ const size_t tileWidth = 2;
+ const size_t tileHeight = 2;
+
+ size_t stride = align(width, tileWidth);
+ size_t size = align(height, tileHeight) * stride * bytesPerPixel + 4;
int err;
if (usage & GRALLOC_USAGE_HW_FB) {
diff --git a/modules/hardware_properties/Android.mk b/modules/hardware_properties/Android.mk
new file mode 100644
index 0000000..41c02ea
--- /dev/null
+++ b/modules/hardware_properties/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2015 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 := hardware_properties.default
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := hardware_properties.c
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/modules/hardware_properties/hardware_properties.c b/modules/hardware_properties/hardware_properties.c
new file mode 100644
index 0000000..89ef423
--- /dev/null
+++ b/modules/hardware_properties/hardware_properties.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "HardwarePropertiesHAL"
+#include <utils/Log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hardware_properties.h>
+
+static ssize_t get_device_temperatures(
+ struct hardware_properties_module *module, float **temps) {
+ *temps = NULL;
+ errno = ENOSYS;
+ ALOGE("getDeviceTemperatures: %s", strerror(errno));
+ return -1;
+}
+
+static ssize_t get_cpu_usages(struct hardware_properties_module *module,
+ int64_t **active_times, int64_t **total_times) {
+ *active_times = NULL;
+ *total_times = NULL;
+ errno = ENOSYS;
+ ALOGE("getCpuUsages: %s", strerror(errno));
+ return -1;
+}
+
+static ssize_t get_fan_speeds(struct hardware_properties_module *module,
+ float **fan_speeds) {
+ *fan_speeds = NULL;
+ errno = ENOSYS;
+ ALOGE("getFanSpeeds: %s", strerror(errno));
+ return -1;
+}
+
+static struct hw_module_methods_t hardware_properties_module_methods = {
+ .open = NULL,
+};
+
+struct hardware_properties_module HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = HARDWARE_PROPERTIES_HARDWARE_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = HARDWARE_PROPERTIES_HARDWARE_MODULE_ID,
+ .name = "Default Hardware Properties HAL",
+ .author = "The Android Open Source Project",
+ .methods = &hardware_properties_module_methods,
+ },
+
+ .getCpuTemperatures = get_device_temperatures,
+ .getGpuTemperatures = get_device_temperatures,
+ .getBatteryTemperatures = get_device_temperatures,
+ .getCpuUsages = get_cpu_usages,
+ .getFanSpeeds = get_fan_speeds,
+};
diff --git a/modules/input/evdev/Android.mk b/modules/input/evdev/Android.mk
index d3c49e7..9a5d092 100644
--- a/modules/input/evdev/Android.mk
+++ b/modules/input/evdev/Android.mk
@@ -18,10 +18,14 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
+ BitUtils.cpp \
InputHub.cpp \
InputDevice.cpp \
InputDeviceManager.cpp \
- InputHost.cpp
+ InputHost.cpp \
+ InputMapper.cpp \
+ MouseInputMapper.cpp \
+ SwitchInputMapper.cpp
LOCAL_SHARED_LIBRARIES := \
libhardware_legacy \
diff --git a/modules/input/evdev/BitUtils.cpp b/modules/input/evdev/BitUtils.cpp
new file mode 100644
index 0000000..3434c31
--- /dev/null
+++ b/modules/input/evdev/BitUtils.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 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 "BitUtils"
+//#define LOG_NDEBUG 0
+
+#include "BitUtils.h"
+
+#include <utils/Log.h>
+
+// Enables debug output for hasKeyInRange
+#define DEBUG_KEY_RANGE 0
+
+namespace android {
+
+#if DEBUG_KEY_RANGE
+static const char* bitstrings[16] = {
+ "0000", "0001", "0010", "0011",
+ "0100", "0101", "0110", "0111",
+ "1000", "1001", "1010", "1011",
+ "1100", "1101", "1110", "1111",
+};
+#endif
+
+bool testBitInRange(const uint8_t arr[], size_t start, size_t end) {
+#if DEBUG_KEY_RANGE
+ ALOGD("testBitInRange(%d, %d)", start, end);
+#endif
+ // Invalid range! This is nonsense; just say no.
+ if (end <= start) return false;
+
+ // Find byte array indices. The end is not included in the range, nor is
+ // endIndex. Round up for endIndex.
+ size_t startIndex = start / 8;
+ size_t endIndex = (end + 7) / 8;
+#if DEBUG_KEY_RANGE
+ ALOGD("startIndex=%d, endIndex=%d", startIndex, endIndex);
+#endif
+ for (size_t i = startIndex; i < endIndex; ++i) {
+ uint8_t bits = arr[i];
+ uint8_t mask = 0xff;
+#if DEBUG_KEY_RANGE
+ ALOGD("block %04d: %s%s", i, bitstrings[bits >> 4], bitstrings[bits & 0x0f]);
+#endif
+ if (bits) {
+ // Mask off bits before our start bit
+ if (i == startIndex) {
+ mask &= 0xff << (start % 8);
+ }
+ // Mask off bits after our end bit
+ if (i == endIndex - 1 && (end % 8)) {
+ mask &= 0xff >> (8 - (end % 8));
+ }
+#if DEBUG_KEY_RANGE
+ ALOGD("mask: %s%s", bitstrings[mask >> 4], bitstrings[mask & 0x0f]);
+#endif
+ // Test the index against the mask
+ if (bits & mask) return true;
+ }
+ }
+ return false;
+}
+} // namespace android
diff --git a/modules/input/evdev/BitUtils.h b/modules/input/evdev/BitUtils.h
new file mode 100644
index 0000000..1aa1f6a
--- /dev/null
+++ b/modules/input/evdev/BitUtils.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 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_BIT_UTILS_H_
+#define ANDROID_BIT_UTILS_H_
+
+#include <cstdint>
+
+namespace android {
+
+/** Test whether any bits in the interval [start, end) are set in the array. */
+bool testBitInRange(const uint8_t arr[], size_t start, size_t end);
+
+} // namespace android
+
+#endif // ANDROID_BIT_UTILS_H_
diff --git a/modules/input/evdev/EvdevModule.cpp b/modules/input/evdev/EvdevModule.cpp
index e9c8222..b37eba1 100644
--- a/modules/input/evdev/EvdevModule.cpp
+++ b/modules/input/evdev/EvdevModule.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
#define LOG_TAG "EvdevModule"
+//#define LOG_NDEBUG 0
#include <memory>
#include <string>
@@ -37,7 +37,8 @@
class EvdevModule {
public:
- explicit EvdevModule(InputHost inputHost);
+ // Takes ownership of the InputHostInterface
+ explicit EvdevModule(InputHostInterface* inputHost);
void init();
void notifyReport(input_report_t* r);
@@ -45,18 +46,18 @@
private:
void loop();
- InputHost mInputHost;
+ std::unique_ptr<InputHostInterface> mInputHost;
std::shared_ptr<InputDeviceManager> mDeviceManager;
- std::shared_ptr<InputHub> mInputHub;
+ std::unique_ptr<InputHub> mInputHub;
std::thread mPollThread;
};
-static std::shared_ptr<EvdevModule> gEvdevModule;
+static std::unique_ptr<EvdevModule> gEvdevModule;
-EvdevModule::EvdevModule(InputHost inputHost) :
+EvdevModule::EvdevModule(InputHostInterface* inputHost) :
mInputHost(inputHost),
- mDeviceManager(std::make_shared<InputDeviceManager>()),
- mInputHub(std::make_shared<InputHub>(mDeviceManager)) {}
+ mDeviceManager(std::make_shared<InputDeviceManager>(mInputHost.get())),
+ mInputHub(std::make_unique<InputHub>(mDeviceManager)) {}
void EvdevModule::init() {
ALOGV("%s", __func__);
@@ -97,8 +98,8 @@
static void input_init(const input_module_t* module,
input_host_t* host, input_host_callbacks_t cb) {
LOG_ALWAYS_FATAL_IF(strcmp(module->common.id, INPUT_HARDWARE_MODULE_ID) != 0);
- InputHost inputHost = {host, cb};
- gEvdevModule = std::make_shared<EvdevModule>(inputHost);
+ auto inputHost = new InputHost(host, cb);
+ gEvdevModule = std::make_unique<EvdevModule>(inputHost);
gEvdevModule->init();
}
diff --git a/modules/input/evdev/InputDevice.cpp b/modules/input/evdev/InputDevice.cpp
index c0b59d7..5f90982 100644
--- a/modules/input/evdev/InputDevice.cpp
+++ b/modules/input/evdev/InputDevice.cpp
@@ -15,37 +15,243 @@
*/
#define LOG_TAG "InputDevice"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
+
+// Enables debug output for processing input events
+#define DEBUG_INPUT_EVENTS 0
+
+#include "InputDevice.h"
#include <linux/input.h>
#define __STDC_FORMAT_MACROS
#include <cinttypes>
+#include <cstdlib>
#include <string>
#include <utils/Log.h>
#include <utils/Timers.h>
+#include "InputHost.h"
#include "InputHub.h"
-#include "InputDevice.h"
+#include "MouseInputMapper.h"
+#include "SwitchInputMapper.h"
#define MSC_ANDROID_TIME_SEC 0x6
#define MSC_ANDROID_TIME_USEC 0x7
namespace android {
-EvdevDevice::EvdevDevice(std::shared_ptr<InputDeviceNode> node) :
- mDeviceNode(node) {}
+static InputBus getInputBus(const std::shared_ptr<InputDeviceNode>& node) {
+ switch (node->getBusType()) {
+ case BUS_USB:
+ return INPUT_BUS_USB;
+ case BUS_BLUETOOTH:
+ return INPUT_BUS_BT;
+ case BUS_RS232:
+ return INPUT_BUS_SERIAL;
+ default:
+ // TODO: check for other linux bus types that might not be built-in
+ return INPUT_BUS_BUILTIN;
+ }
+}
+
+static uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
+ // Touch devices get dibs on touch-related axes.
+ if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) {
+ switch (axis) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_PRESSURE:
+ case ABS_TOOL_WIDTH:
+ case ABS_DISTANCE:
+ case ABS_TILT_X:
+ case ABS_TILT_Y:
+ case ABS_MT_SLOT:
+ case ABS_MT_TOUCH_MAJOR:
+ case ABS_MT_TOUCH_MINOR:
+ case ABS_MT_WIDTH_MAJOR:
+ case ABS_MT_WIDTH_MINOR:
+ case ABS_MT_ORIENTATION:
+ case ABS_MT_POSITION_X:
+ case ABS_MT_POSITION_Y:
+ case ABS_MT_TOOL_TYPE:
+ case ABS_MT_BLOB_ID:
+ case ABS_MT_TRACKING_ID:
+ case ABS_MT_PRESSURE:
+ case ABS_MT_DISTANCE:
+ return INPUT_DEVICE_CLASS_TOUCH;
+ }
+ }
+
+ // External stylus gets the pressure axis
+ if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ if (axis == ABS_PRESSURE) {
+ return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+ }
+ }
+
+ // Joystick devices get the rest.
+ return INPUT_DEVICE_CLASS_JOYSTICK;
+}
+
+static bool getBooleanProperty(const InputProperty& prop) {
+ const char* propValue = prop.getValue();
+ if (propValue == nullptr) return false;
+
+ char* end;
+ int value = std::strtol(propValue, &end, 10);
+ if (*end != '\0') {
+ ALOGW("Expected boolean for property %s; value=%s", prop.getKey(), propValue);
+ return false;
+ }
+ return value;
+}
+
+EvdevDevice::EvdevDevice(InputHostInterface* host, const std::shared_ptr<InputDeviceNode>& node) :
+ mHost(host), mDeviceNode(node), mDeviceDefinition(mHost->createDeviceDefinition()) {
+
+ InputBus bus = getInputBus(node);
+ mInputId = mHost->createDeviceIdentifier(
+ node->getName().c_str(),
+ node->getProductId(),
+ node->getVendorId(),
+ bus,
+ node->getUniqueId().c_str());
+
+ createMappers();
+ configureDevice();
+
+ // If we found a need for at least one mapper, register the device with the
+ // host. If there were no mappers, this device is effectively ignored, as
+ // the host won't know about it.
+ if (mMappers.size() > 0) {
+ mDeviceHandle = mHost->registerDevice(mInputId, mDeviceDefinition);
+ for (const auto& mapper : mMappers) {
+ mapper->setDeviceHandle(mDeviceHandle);
+ }
+ }
+}
+
+void EvdevDevice::createMappers() {
+ // See if this is a cursor device such as a trackball or mouse.
+ if (mDeviceNode->hasKey(BTN_MOUSE)
+ && mDeviceNode->hasRelativeAxis(REL_X)
+ && mDeviceNode->hasRelativeAxis(REL_Y)) {
+ mClasses |= INPUT_DEVICE_CLASS_CURSOR;
+ mMappers.push_back(std::make_unique<MouseInputMapper>());
+ }
+
+ bool isStylus = false;
+ bool haveGamepadButtons = mDeviceNode->hasKeyInRange(BTN_MISC, BTN_MOUSE) ||
+ mDeviceNode->hasKeyInRange(BTN_JOYSTICK, BTN_DIGI);
+
+ // See if this is a touch pad or stylus.
+ // Is this a new modern multi-touch driver?
+ if (mDeviceNode->hasAbsoluteAxis(ABS_MT_POSITION_X)
+ && mDeviceNode->hasAbsoluteAxis(ABS_MT_POSITION_Y)) {
+ // Some joysticks such as the PS3 controller report axes that conflict
+ // with the ABS_MT range. Try to confirm that the device really is a
+ // touch screen.
+ if (mDeviceNode->hasKey(BTN_TOUCH) || !haveGamepadButtons) {
+ mClasses |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
+ //mMappers.push_back(std::make_unique<MultiTouchInputMapper>());
+ }
+ // Is this an old style single-touch driver?
+ } else if (mDeviceNode->hasKey(BTN_TOUCH)
+ && mDeviceNode->hasAbsoluteAxis(ABS_X)
+ && mDeviceNode->hasAbsoluteAxis(ABS_Y)) {
+ mClasses |= INPUT_DEVICE_CLASS_TOUCH;
+ //mMappers.push_back(std::make_unique<SingleTouchInputMapper>());
+ // Is this a BT stylus?
+ } else if ((mDeviceNode->hasAbsoluteAxis(ABS_PRESSURE) || mDeviceNode->hasKey(BTN_TOUCH))
+ && !mDeviceNode->hasAbsoluteAxis(ABS_X) && !mDeviceNode->hasAbsoluteAxis(ABS_Y)) {
+ mClasses |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+ //mMappers.push_back(std::make_unique<ExternalStylusInputMapper>());
+ isStylus = true;
+ mClasses &= ~INPUT_DEVICE_CLASS_KEYBOARD;
+ }
+
+ // See if this is a keyboard. Ignore everything in the button range except
+ // for joystick and gamepad buttons which are handled like keyboards for the
+ // most part.
+ // Keyboard will try to claim some of the stylus buttons but we really want
+ // to reserve those so we can fuse it with the touch screen data. Note this
+ // means an external stylus cannot also be a keyboard device.
+ if (!isStylus) {
+ bool haveKeyboardKeys = mDeviceNode->hasKeyInRange(0, BTN_MISC) ||
+ mDeviceNode->hasKeyInRange(KEY_OK, KEY_CNT);
+ if (haveKeyboardKeys || haveGamepadButtons) {
+ mClasses |= INPUT_DEVICE_CLASS_KEYBOARD;
+ //mMappers.push_back(std::make_unique<KeyboardInputMapper>());
+ }
+ }
+
+ // See if this device is a joystick.
+ // Assumes that joysticks always have gamepad buttons in order to
+ // distinguish them from other devices such as accelerometers that also have
+ // absolute axes.
+ if (haveGamepadButtons) {
+ uint32_t assumedClasses = mClasses | INPUT_DEVICE_CLASS_JOYSTICK;
+ for (int i = 0; i < ABS_CNT; ++i) {
+ if (mDeviceNode->hasAbsoluteAxis(i)
+ && getAbsAxisUsage(i, assumedClasses) == INPUT_DEVICE_CLASS_JOYSTICK) {
+ mClasses = assumedClasses;
+ //mMappers.push_back(std::make_unique<JoystickInputMapper>());
+ break;
+ }
+ }
+ }
+
+ // Check whether this device has switches.
+ for (int i = 0; i < SW_CNT; ++i) {
+ if (mDeviceNode->hasSwitch(i)) {
+ mClasses |= INPUT_DEVICE_CLASS_SWITCH;
+ mMappers.push_back(std::make_unique<SwitchInputMapper>());
+ break;
+ }
+ }
+
+ // Check whether this device supports the vibrator.
+ // TODO: decide if this is necessary.
+ if (mDeviceNode->hasForceFeedback(FF_RUMBLE)) {
+ mClasses |= INPUT_DEVICE_CLASS_VIBRATOR;
+ //mMappers.push_back(std::make_unique<VibratorInputMapper>());
+ }
+
+ ALOGD("device %s classes=0x%x %zu mappers", mDeviceNode->getPath().c_str(), mClasses,
+ mMappers.size());
+}
+
+void EvdevDevice::configureDevice() {
+ for (const auto& mapper : mMappers) {
+ auto reportDef = mHost->createInputReportDefinition();
+ if (mapper->configureInputReport(mDeviceNode.get(), reportDef)) {
+ mDeviceDefinition->addReport(reportDef);
+ } else {
+ mHost->freeReportDefinition(reportDef);
+ }
+
+ reportDef = mHost->createOutputReportDefinition();
+ if (mapper->configureOutputReport(mDeviceNode.get(), reportDef)) {
+ mDeviceDefinition->addReport(reportDef);
+ } else {
+ mHost->freeReportDefinition(reportDef);
+ }
+ }
+}
void EvdevDevice::processInput(InputEvent& event, nsecs_t currentTime) {
+#if DEBUG_INPUT_EVENTS
std::string log;
log.append("---InputEvent for device %s---\n");
log.append(" when: %" PRId64 "\n");
log.append(" type: %d\n");
log.append(" code: %d\n");
log.append(" value: %d\n");
- ALOGV(log.c_str(), mDeviceNode->getPath().c_str(), event.when, event.type, event.code,
+ ALOGD(log.c_str(), mDeviceNode->getPath().c_str(), event.when, event.type, event.code,
event.value);
+#endif
if (event.type == EV_MSC) {
if (event.code == MSC_ANDROID_TIME_SEC) {
@@ -97,6 +303,10 @@
", call time %" PRId64 ".", event.when, time, currentTime);
}
}
+
+ for (size_t i = 0; i < mMappers.size(); ++i) {
+ mMappers[i]->process(event);
+ }
}
} // namespace android
diff --git a/modules/input/evdev/InputDevice.h b/modules/input/evdev/InputDevice.h
index 3aa16cc..6892778 100644
--- a/modules/input/evdev/InputDevice.h
+++ b/modules/input/evdev/InputDevice.h
@@ -18,13 +18,24 @@
#define ANDROID_INPUT_DEVICE_H_
#include <memory>
+#include <vector>
#include <utils/Timers.h>
-#include "InputHub.h"
+#include "InputMapper.h"
+
+struct input_device_handle;
+struct input_device_identifier;
namespace android {
+class InputDeviceDefinition;
+class InputDeviceNode;
+class InputHostInterface;
+struct InputEvent;
+using InputDeviceHandle = struct input_device_handle;
+using InputDeviceIdentifier = struct input_device_identifier;
+
/**
* InputDeviceInterface represents an input device in the HAL. It processes
* input events before passing them to the input host.
@@ -33,6 +44,7 @@
public:
virtual void processInput(InputEvent& event, nsecs_t currentTime) = 0;
+ virtual uint32_t getInputClasses() = 0;
protected:
InputDeviceInterface() = default;
virtual ~InputDeviceInterface() = default;
@@ -43,18 +55,75 @@
*/
class EvdevDevice : public InputDeviceInterface {
public:
- explicit EvdevDevice(std::shared_ptr<InputDeviceNode> node);
+ EvdevDevice(InputHostInterface* host, const std::shared_ptr<InputDeviceNode>& node);
virtual ~EvdevDevice() override = default;
virtual void processInput(InputEvent& event, nsecs_t currentTime) override;
+ virtual uint32_t getInputClasses() override { return mClasses; }
private:
+ void createMappers();
+ void configureDevice();
+
+ InputHostInterface* mHost = nullptr;
std::shared_ptr<InputDeviceNode> mDeviceNode;
+ InputDeviceIdentifier* mInputId = nullptr;
+ InputDeviceDefinition* mDeviceDefinition = nullptr;
+ InputDeviceHandle* mDeviceHandle = nullptr;
+ std::vector<std::unique_ptr<InputMapper>> mMappers;
+ uint32_t mClasses = 0;
int32_t mOverrideSec = 0;
int32_t mOverrideUsec = 0;
};
+/* Input device classes. */
+enum {
+ /* The input device is a keyboard or has buttons. */
+ INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001,
+
+ /* The input device is an alpha-numeric keyboard (not just a dial pad). */
+ INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002,
+
+ /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
+ INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
+
+ /* The input device is a cursor device such as a trackball or mouse. */
+ INPUT_DEVICE_CLASS_CURSOR = 0x00000008,
+
+ /* The input device is a multi-touch touchscreen. */
+ INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,
+
+ /* The input device is a directional pad (implies keyboard, has DPAD keys). */
+ INPUT_DEVICE_CLASS_DPAD = 0x00000020,
+
+ /* The input device is a gamepad (implies keyboard, has BUTTON keys). */
+ INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040,
+
+ /* The input device has switches. */
+ INPUT_DEVICE_CLASS_SWITCH = 0x00000080,
+
+ /* The input device is a joystick (implies gamepad, has joystick absolute axes). */
+ INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100,
+
+ /* The input device has a vibrator (supports FF_RUMBLE). */
+ INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200,
+
+ /* The input device has a microphone. */
+ // TODO: remove this and let the host take care of it
+ INPUT_DEVICE_CLASS_MIC = 0x00000400,
+
+ /* The input device is an external stylus (has data we want to fuse with touch data). */
+ INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,
+
+ /* The input device is virtual (not a real device, not part of UI configuration). */
+ /* not used - INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, */
+
+ /* The input device is external (not built-in). */
+ // TODO: remove this and let the host take care of it?
+ INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
+};
+
} // namespace android
#endif // ANDROID_INPUT_DEVICE_H_
diff --git a/modules/input/evdev/InputDeviceManager.cpp b/modules/input/evdev/InputDeviceManager.cpp
index ceddd90..d50c1ae 100644
--- a/modules/input/evdev/InputDeviceManager.cpp
+++ b/modules/input/evdev/InputDeviceManager.cpp
@@ -17,14 +17,15 @@
#define LOG_TAG "InputDeviceManager"
//#define LOG_NDEBUG 0
+#include "InputDeviceManager.h"
+
#include <utils/Log.h>
#include "InputDevice.h"
-#include "InputDeviceManager.h"
namespace android {
-void InputDeviceManager::onInputEvent(std::shared_ptr<InputDeviceNode> node, InputEvent& event,
+void InputDeviceManager::onInputEvent(const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
nsecs_t event_time) {
if (mDevices[node] == nullptr) {
ALOGE("got input event for unknown node %s", node->getPath().c_str());
@@ -33,17 +34,18 @@
mDevices[node]->processInput(event, event_time);
}
-void InputDeviceManager::onDeviceAdded(std::shared_ptr<InputDeviceNode> node) {
- mDevices[node] = std::make_shared<EvdevDevice>(node);
+void InputDeviceManager::onDeviceAdded(const std::shared_ptr<InputDeviceNode>& node) {
+ mDevices[node] = std::make_shared<EvdevDevice>(mHost, node);
}
-void InputDeviceManager::onDeviceRemoved(std::shared_ptr<InputDeviceNode> node) {
+void InputDeviceManager::onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) {
if (mDevices[node] == nullptr) {
ALOGE("could not remove unknown node %s", node->getPath().c_str());
return;
}
// TODO: tell the InputDevice and InputDeviceNode that they are being
- // removed so they can run any cleanup.
+ // removed so they can run any cleanup, including unregistering from the
+ // host.
mDevices.erase(node);
}
diff --git a/modules/input/evdev/InputDeviceManager.h b/modules/input/evdev/InputDeviceManager.h
index b652155..8fbf3ca 100644
--- a/modules/input/evdev/InputDeviceManager.h
+++ b/modules/input/evdev/InputDeviceManager.h
@@ -22,11 +22,13 @@
#include <utils/Timers.h>
-#include "InputDevice.h"
#include "InputHub.h"
namespace android {
+class InputDeviceInterface;
+class InputHostInterface;
+
/**
* InputDeviceManager keeps the mapping of InputDeviceNodes to
* InputDeviceInterfaces and handles the callbacks from the InputHub, delegating
@@ -34,14 +36,18 @@
*/
class InputDeviceManager : public InputCallbackInterface {
public:
+ explicit InputDeviceManager(InputHostInterface* host) :
+ mHost(host) {}
virtual ~InputDeviceManager() override = default;
- virtual void onInputEvent(std::shared_ptr<InputDeviceNode> node, InputEvent& event,
+ virtual void onInputEvent(const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
nsecs_t event_time) override;
- virtual void onDeviceAdded(std::shared_ptr<InputDeviceNode> node) override;
- virtual void onDeviceRemoved(std::shared_ptr<InputDeviceNode> node) override;
+ virtual void onDeviceAdded(const std::shared_ptr<InputDeviceNode>& node) override;
+ virtual void onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) override;
private:
+ InputHostInterface* mHost;
+
template<class T, class U>
using DeviceMap = std::unordered_map<std::shared_ptr<T>, std::shared_ptr<U>>;
diff --git a/modules/input/evdev/InputHost.cpp b/modules/input/evdev/InputHost.cpp
index 6a65fcd..5be4a79 100644
--- a/modules/input/evdev/InputHost.cpp
+++ b/modules/input/evdev/InputHost.cpp
@@ -18,7 +18,17 @@
namespace android {
-void InputReport::reportEvent(InputDeviceHandle d) {
+void InputReport::setIntUsage(InputCollectionId id, InputUsage usage, int32_t value,
+ int32_t arityIndex) {
+ mCallbacks.input_report_set_usage_int(mHost, mReport, id, usage, value, arityIndex);
+}
+
+void InputReport::setBoolUsage(InputCollectionId id, InputUsage usage, bool value,
+ int32_t arityIndex) {
+ mCallbacks.input_report_set_usage_bool(mHost, mReport, id, usage, value, arityIndex);
+}
+
+void InputReport::reportEvent(InputDeviceHandle* d) {
mCallbacks.report_event(mHost, d, mReport);
}
@@ -32,73 +42,78 @@
id, usage, min, max, resolution);
}
-void InputReportDefinition::declareUsage(InputCollectionId id, InputUsage* usage,
+void InputReportDefinition::declareUsages(InputCollectionId id, InputUsage* usage,
size_t usageCount) {
mCallbacks.input_report_definition_declare_usages_bool(mHost, mReportDefinition,
id, usage, usageCount);
}
-InputReport InputReportDefinition::allocateReport() {
- return InputReport(mHost, mCallbacks,
+InputReport* InputReportDefinition::allocateReport() {
+ return new InputReport(mHost, mCallbacks,
mCallbacks.input_allocate_report(mHost, mReportDefinition));
}
-void InputDeviceDefinition::addReport(InputReportDefinition r) {
- mCallbacks.input_device_definition_add_report(mHost, mDeviceDefinition, r);
+void InputDeviceDefinition::addReport(InputReportDefinition* r) {
+ mCallbacks.input_device_definition_add_report(mHost, mDeviceDefinition, *r);
}
-InputProperty::~InputProperty() {
- mCallbacks.input_free_device_property(mHost, mProperty);
-}
-
-const char* InputProperty::getKey() {
+const char* InputProperty::getKey() const {
return mCallbacks.input_get_property_key(mHost, mProperty);
}
-const char* InputProperty::getValue() {
+const char* InputProperty::getValue() const {
return mCallbacks.input_get_property_value(mHost, mProperty);
}
-InputPropertyMap::~InputPropertyMap() {
- mCallbacks.input_free_device_property_map(mHost, mMap);
-}
-
-InputProperty InputPropertyMap::getDeviceProperty(const char* key) {
- return InputProperty(mHost, mCallbacks,
+InputProperty* InputPropertyMap::getDeviceProperty(const char* key) const {
+ return new InputProperty(mHost, mCallbacks,
mCallbacks.input_get_device_property(mHost, mMap, key));
}
-InputDeviceIdentifier InputHost::createDeviceIdentifier(const char* name, int32_t productId,
+void InputPropertyMap::freeDeviceProperty(InputProperty* property) const {
+ mCallbacks.input_free_device_property(mHost, *property);
+}
+
+InputDeviceIdentifier* InputHost::createDeviceIdentifier(const char* name, int32_t productId,
int32_t vendorId, InputBus bus, const char* uniqueId) {
- return mCallbacks.create_device_identifier(mHost, name, productId, vendorId, bus, uniqueId);
+ return mCallbacks.create_device_identifier(
+ mHost, name, productId, vendorId, bus, uniqueId);
}
-InputDeviceDefinition InputHost::createDeviceDefinition() {
- return InputDeviceDefinition(mHost, mCallbacks, mCallbacks.create_device_definition(mHost));
+InputDeviceDefinition* InputHost::createDeviceDefinition() {
+ return new InputDeviceDefinition(mHost, mCallbacks, mCallbacks.create_device_definition(mHost));
}
-InputReportDefinition InputHost::createInputReportDefinition() {
- return InputReportDefinition(mHost, mCallbacks,
+InputReportDefinition* InputHost::createInputReportDefinition() {
+ return new InputReportDefinition(mHost, mCallbacks,
mCallbacks.create_input_report_definition(mHost));
}
-InputReportDefinition InputHost::createOutputReportDefinition() {
- return InputReportDefinition(mHost, mCallbacks,
+InputReportDefinition* InputHost::createOutputReportDefinition() {
+ return new InputReportDefinition(mHost, mCallbacks,
mCallbacks.create_output_report_definition(mHost));
}
-InputDeviceHandle InputHost::registerDevice(InputDeviceIdentifier id,
- InputDeviceDefinition d) {
- return mCallbacks.register_device(mHost, id, d);
+void InputHost::freeReportDefinition(InputReportDefinition* reportDef) {
+ mCallbacks.free_report_definition(mHost, *reportDef);
}
-void InputHost::unregisterDevice(InputDeviceHandle handle) {
- return mCallbacks.unregister_device(mHost, handle);
+InputDeviceHandle* InputHost::registerDevice(InputDeviceIdentifier* id,
+ InputDeviceDefinition* d) {
+ return mCallbacks.register_device(mHost, id, *d);
}
-InputPropertyMap InputHost::getDevicePropertyMap(InputDeviceIdentifier id) {
- return InputPropertyMap(mHost, mCallbacks,
+void InputHost::unregisterDevice(InputDeviceHandle* handle) {
+ mCallbacks.unregister_device(mHost, handle);
+}
+
+InputPropertyMap* InputHost::getDevicePropertyMap(InputDeviceIdentifier* id) {
+ return new InputPropertyMap(mHost, mCallbacks,
mCallbacks.input_get_device_property_map(mHost, id));
}
+void InputHost::freeDevicePropertyMap(InputPropertyMap* propertyMap) {
+ mCallbacks.input_free_device_property_map(mHost, *propertyMap);
+}
+
} // namespace android
diff --git a/modules/input/evdev/InputHost.h b/modules/input/evdev/InputHost.h
index 98ce26f..d6573d2 100644
--- a/modules/input/evdev/InputHost.h
+++ b/modules/input/evdev/InputHost.h
@@ -25,17 +25,17 @@
/**
* Classes in this file wrap the corresponding interfaces in the Input HAL. They
- * are intended to be lightweight and passed by value. It is still important not
- * to use an object after a HAL-specific method has freed the underlying
- * representation.
+ * are intended to be lightweight, as they primarily wrap pointers to callbacks.
+ * It is still important not to use an object after a HAL-specific method has
+ * freed the underlying representation.
*
* See hardware/input.h for details about each of these methods.
*/
using InputBus = input_bus_t;
using InputCollectionId = input_collection_id_t;
-using InputDeviceHandle = input_device_handle_t*;
-using InputDeviceIdentifier = input_device_identifier_t*;
+using InputDeviceHandle = input_device_handle_t;
+using InputDeviceIdentifier = input_device_identifier_t;
using InputUsage = input_usage_t;
class InputHostBase {
@@ -43,148 +43,148 @@
InputHostBase(input_host_t* host, input_host_callbacks_t cb) : mHost(host), mCallbacks(cb) {}
virtual ~InputHostBase() = default;
+ InputHostBase(const InputHostBase& rhs) = delete;
+ InputHostBase(InputHostBase&& rhs) = delete;
+
input_host_t* mHost;
input_host_callbacks_t mCallbacks;
};
class InputReport : private InputHostBase {
public:
- virtual ~InputReport() = default;
-
- InputReport(const InputReport& rhs) = default;
- InputReport& operator=(const InputReport& rhs) = default;
- operator input_report_t*() const { return mReport; }
-
- void reportEvent(InputDeviceHandle d);
-
-private:
- friend class InputReportDefinition;
-
InputReport(input_host_t* host, input_host_callbacks_t cb, input_report_t* r) :
InputHostBase(host, cb), mReport(r) {}
+ virtual ~InputReport() = default;
+ virtual void setIntUsage(InputCollectionId id, InputUsage usage, int32_t value,
+ int32_t arityIndex);
+ virtual void setBoolUsage(InputCollectionId id, InputUsage usage, bool value,
+ int32_t arityIndex);
+ virtual void reportEvent(InputDeviceHandle* d);
+
+ operator input_report_t*() const { return mReport; }
+
+ InputReport(const InputReport& rhs) = delete;
+ InputReport& operator=(const InputReport& rhs) = delete;
+private:
input_report_t* mReport;
};
class InputReportDefinition : private InputHostBase {
public:
+ InputReportDefinition(input_host_t* host, input_host_callbacks_t cb,
+ input_report_definition_t* r) : InputHostBase(host, cb), mReportDefinition(r) {}
virtual ~InputReportDefinition() = default;
- InputReportDefinition(const InputReportDefinition& rhs) = default;
- InputReportDefinition& operator=(const InputReportDefinition& rhs) = default;
+ virtual void addCollection(InputCollectionId id, int32_t arity);
+ virtual void declareUsage(InputCollectionId id, InputUsage usage, int32_t min, int32_t max,
+ float resolution);
+ virtual void declareUsages(InputCollectionId id, InputUsage* usage, size_t usageCount);
+
+ virtual InputReport* allocateReport();
+
operator input_report_definition_t*() { return mReportDefinition; }
- void addCollection(InputCollectionId id, int32_t arity);
- void declareUsage(InputCollectionId id, InputUsage usage, int32_t min, int32_t max,
- float resolution);
- void declareUsage(InputCollectionId id, InputUsage* usage, size_t usageCount);
-
- InputReport allocateReport();
-
+ InputReportDefinition(const InputReportDefinition& rhs) = delete;
+ InputReportDefinition& operator=(const InputReportDefinition& rhs) = delete;
private:
- friend class InputHost;
-
- InputReportDefinition(
- input_host_t* host, input_host_callbacks_t cb, input_report_definition_t* r) :
- InputHostBase(host, cb), mReportDefinition(r) {}
-
input_report_definition_t* mReportDefinition;
};
class InputDeviceDefinition : private InputHostBase {
public:
+ InputDeviceDefinition(input_host_t* host, input_host_callbacks_t cb,
+ input_device_definition_t* d) :
+ InputHostBase(host, cb), mDeviceDefinition(d) {}
virtual ~InputDeviceDefinition() = default;
- InputDeviceDefinition(const InputDeviceDefinition& rhs) = default;
- InputDeviceDefinition& operator=(const InputDeviceDefinition& rhs) = default;
+ virtual void addReport(InputReportDefinition* r);
+
operator input_device_definition_t*() { return mDeviceDefinition; }
- void addReport(InputReportDefinition r);
-
+ InputDeviceDefinition(const InputDeviceDefinition& rhs) = delete;
+ InputDeviceDefinition& operator=(const InputDeviceDefinition& rhs) = delete;
private:
- friend class InputHost;
-
- InputDeviceDefinition(
- input_host_t* host, input_host_callbacks_t cb, input_device_definition_t* d) :
- InputHostBase(host, cb), mDeviceDefinition(d) {}
-
input_device_definition_t* mDeviceDefinition;
};
class InputProperty : private InputHostBase {
public:
- virtual ~InputProperty();
+ virtual ~InputProperty() = default;
+
+ InputProperty(input_host_t* host, input_host_callbacks_t cb, input_property_t* p) :
+ InputHostBase(host, cb), mProperty(p) {}
+
+ virtual const char* getKey() const;
+ virtual const char* getValue() const;
operator input_property_t*() { return mProperty; }
- const char* getKey();
- const char* getValue();
-
- // Default move constructor transfers ownership of the input_property_t
- // pointer.
- InputProperty(InputProperty&& rhs) = default;
-
- // Prevent copy/assign because of the ownership of the underlying
- // input_property_t pointer.
InputProperty(const InputProperty& rhs) = delete;
InputProperty& operator=(const InputProperty& rhs) = delete;
-
private:
- friend class InputPropertyMap;
-
- InputProperty(
- input_host_t* host, input_host_callbacks_t cb, input_property_t* p) :
- InputHostBase(host, cb), mProperty(p) {}
-
input_property_t* mProperty;
};
class InputPropertyMap : private InputHostBase {
public:
- virtual ~InputPropertyMap();
+ virtual ~InputPropertyMap() = default;
+
+ InputPropertyMap(input_host_t* host, input_host_callbacks_t cb, input_property_map_t* m) :
+ InputHostBase(host, cb), mMap(m) {}
+
+ virtual InputProperty* getDeviceProperty(const char* key) const;
+ virtual void freeDeviceProperty(InputProperty* property) const;
operator input_property_map_t*() { return mMap; }
- InputProperty getDeviceProperty(const char* key);
-
- // Default move constructor transfers ownership of the input_property_map_t
- // pointer.
- InputPropertyMap(InputPropertyMap&& rhs) = default;
-
- // Prevent copy/assign because of the ownership of the underlying
- // input_property_map_t pointer.
InputPropertyMap(const InputPropertyMap& rhs) = delete;
InputPropertyMap& operator=(const InputPropertyMap& rhs) = delete;
-
private:
- friend class InputHost;
-
- InputPropertyMap(
- input_host_t* host, input_host_callbacks_t cb, input_property_map_t* m) :
- InputHostBase(host, cb), mMap(m) {}
-
input_property_map_t* mMap;
};
-class InputHost : private InputHostBase {
+class InputHostInterface {
+public:
+ virtual ~InputHostInterface() = default;
+
+ virtual InputDeviceIdentifier* createDeviceIdentifier(const char* name, int32_t productId,
+ int32_t vendorId, InputBus bus, const char* uniqueId) = 0;
+
+ virtual InputDeviceDefinition* createDeviceDefinition() = 0;
+ virtual InputReportDefinition* createInputReportDefinition() = 0;
+ virtual InputReportDefinition* createOutputReportDefinition() = 0;
+ virtual void freeReportDefinition(InputReportDefinition* reportDef) = 0;
+
+ virtual InputDeviceHandle* registerDevice(InputDeviceIdentifier* id,
+ InputDeviceDefinition* d) = 0;
+ virtual void unregisterDevice(InputDeviceHandle* handle) = 0;
+
+ virtual InputPropertyMap* getDevicePropertyMap(InputDeviceIdentifier* id) = 0;
+ virtual void freeDevicePropertyMap(InputPropertyMap* propertyMap) = 0;
+};
+
+class InputHost : public InputHostInterface, private InputHostBase {
public:
InputHost(input_host_t* host, input_host_callbacks_t cb) : InputHostBase(host, cb) {}
virtual ~InputHost() = default;
- InputHost(const InputHost& rhs) = default;
- InputHost& operator=(const InputHost& rhs) = default;
+ InputDeviceIdentifier* createDeviceIdentifier(const char* name, int32_t productId,
+ int32_t vendorId, InputBus bus, const char* uniqueId) override;
- InputDeviceIdentifier createDeviceIdentifier(const char* name, int32_t productId,
- int32_t vendorId, InputBus bus, const char* uniqueId);
+ InputDeviceDefinition* createDeviceDefinition() override;
+ InputReportDefinition* createInputReportDefinition() override;
+ InputReportDefinition* createOutputReportDefinition() override;
+ virtual void freeReportDefinition(InputReportDefinition* reportDef) override;
- InputDeviceDefinition createDeviceDefinition();
- InputReportDefinition createInputReportDefinition();
- InputReportDefinition createOutputReportDefinition();
+ InputDeviceHandle* registerDevice(InputDeviceIdentifier* id, InputDeviceDefinition* d) override;
+ void unregisterDevice(InputDeviceHandle* handle) override;
- InputDeviceHandle registerDevice(InputDeviceIdentifier id, InputDeviceDefinition d);
- void unregisterDevice(InputDeviceHandle handle);
+ InputPropertyMap* getDevicePropertyMap(InputDeviceIdentifier* id) override;
+ void freeDevicePropertyMap(InputPropertyMap* propertyMap) override;
- InputPropertyMap getDevicePropertyMap(InputDeviceIdentifier id);
+ InputHost(const InputHost& rhs) = delete;
+ InputHost& operator=(const InputHost& rhs) = delete;
};
} // namespace android
diff --git a/modules/input/evdev/InputHub.cpp b/modules/input/evdev/InputHub.cpp
index e72ac2e..389955d 100644
--- a/modules/input/evdev/InputHub.cpp
+++ b/modules/input/evdev/InputHub.cpp
@@ -15,7 +15,9 @@
*/
#define LOG_TAG "InputHub"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
+
+#include "InputHub.h"
#include <dirent.h>
#include <errno.h>
@@ -33,14 +35,14 @@
#include <vector>
-#include "InputHub.h"
-
#include <android/input.h>
#include <hardware_legacy/power.h>
#include <linux/input.h>
#include <utils/Log.h>
+#include "BitUtils.h"
+
namespace android {
static const char WAKE_LOCK_ID[] = "KeyEvents";
@@ -74,7 +76,6 @@
caphdr->version = _LINUX_CAPABILITY_VERSION_3;
LOG_ALWAYS_FATAL_IF(capget(caphdr, capdata) != 0,
"Could not get process capabilities. errno=%d", errno);
- ALOGV("effective capabilities: %08x %08x", capdata[0].effective, capdata[1].effective);
int idx = CAP_TO_INDEX(capability);
return capdata[idx].effective & CAP_TO_MASK(capability);
}
@@ -102,16 +103,20 @@
virtual uint16_t getVersion() const override { return mVersion; }
virtual bool hasKey(int32_t key) const override;
- virtual bool hasRelativeAxis(int axis) const override;
- virtual const AbsoluteAxisInfo* getAbsoluteAxisInfo(int32_t axis) const override;
+ virtual bool hasKeyInRange(int32_t start, int32_t end) const override;
+ virtual bool hasRelativeAxis(int32_t axis) const override;
+ virtual bool hasAbsoluteAxis(int32_t axis) const override;
+ virtual bool hasSwitch(int32_t sw) const override;
+ virtual bool hasForceFeedback(int32_t ff) const override;
virtual bool hasInputProperty(int property) const override;
virtual int32_t getKeyState(int32_t key) const override;
virtual int32_t getSwitchState(int32_t sw) const override;
+ virtual const AbsoluteAxisInfo* getAbsoluteAxisInfo(int32_t axis) const override;
virtual status_t getAbsoluteAxisValue(int32_t axis, int32_t* outValue) const override;
virtual void vibrate(nsecs_t duration) override;
- virtual void cancelVibrate(int32_t deviceId) override;
+ virtual void cancelVibrate() override;
virtual void disableDriverKeyRepeat() override;
@@ -272,6 +277,10 @@
return false;
}
+bool EvdevDeviceNode::hasKeyInRange(int32_t startKey, int32_t endKey) const {
+ return testBitInRange(mKeyBitmask, startKey, endKey);
+}
+
bool EvdevDeviceNode::hasRelativeAxis(int axis) const {
if (axis >= 0 && axis <= REL_MAX) {
return testBit(axis, mRelBitmask);
@@ -279,6 +288,13 @@
return false;
}
+bool EvdevDeviceNode::hasAbsoluteAxis(int axis) const {
+ if (axis >= 0 && axis <= ABS_MAX) {
+ return getAbsoluteAxisInfo(axis) != nullptr;
+ }
+ return false;
+}
+
const AbsoluteAxisInfo* EvdevDeviceNode::getAbsoluteAxisInfo(int32_t axis) const {
if (axis < 0 || axis > ABS_MAX) {
return nullptr;
@@ -291,6 +307,20 @@
return nullptr;
}
+bool EvdevDeviceNode::hasSwitch(int32_t sw) const {
+ if (sw >= 0 && sw <= SW_MAX) {
+ return testBit(sw, mSwBitmask);
+ }
+ return false;
+}
+
+bool EvdevDeviceNode::hasForceFeedback(int32_t ff) const {
+ if (ff >= 0 && ff <= FF_MAX) {
+ return testBit(ff, mFfBitmask);
+ }
+ return false;
+}
+
bool EvdevDeviceNode::hasInputProperty(int property) const {
if (property >= 0 && property <= INPUT_PROP_MAX) {
return testBit(property, mPropBitmask);
@@ -371,7 +401,7 @@
mFfEffectPlaying = true;
}
-void EvdevDeviceNode::cancelVibrate(int32_t deviceId) {
+void EvdevDeviceNode::cancelVibrate() {
if (mFfEffectPlaying) {
mFfEffectPlaying = false;
@@ -396,7 +426,7 @@
}
}
-InputHub::InputHub(std::shared_ptr<InputCallbackInterface> cb) :
+InputHub::InputHub(const std::shared_ptr<InputCallbackInterface>& cb) :
mInputCallback(cb) {
// Determine the type of suspend blocking we can do on this device. There
// are 3 options, in decreasing order of preference:
@@ -670,9 +700,8 @@
ALOGV("inotify event for path %s", path.c_str());
if (event->mask & IN_CREATE) {
- std::shared_ptr<InputDeviceNode> deviceNode;
- status_t res = openNode(path, &deviceNode);
- if (res != OK) {
+ auto deviceNode = openNode(path);
+ if (deviceNode == nullptr) {
ALOGE("could not open device node %s. err=%d", path.c_str(), res);
} else {
mInputCallback->onDeviceAdded(deviceNode);
@@ -680,7 +709,7 @@
} else {
auto deviceNode = findNodeByPath(path);
if (deviceNode != nullptr) {
- status_t ret = closeNode(deviceNode);
+ status_t ret = closeNode(deviceNode.get());
if (ret != OK) {
ALOGW("Could not close device %s. errno=%d", path.c_str(), ret);
} else {
@@ -712,8 +741,8 @@
continue;
}
std::string filename = path + "/" + dirent->d_name;
- std::shared_ptr<InputDeviceNode> node;
- if (openNode(filename, &node) != OK) {
+ auto node = openNode(filename);
+ if (node == nullptr) {
ALOGE("could not open device node %s", filename.c_str());
} else {
mInputCallback->onDeviceAdded(node);
@@ -723,18 +752,16 @@
return OK;
}
-status_t InputHub::openNode(const std::string& path,
- std::shared_ptr<InputDeviceNode>* outNode) {
+std::shared_ptr<InputDeviceNode> InputHub::openNode(const std::string& path) {
ALOGV("opening %s...", path.c_str());
auto evdevNode = std::shared_ptr<EvdevDeviceNode>(EvdevDeviceNode::openDeviceNode(path));
if (evdevNode == nullptr) {
- return UNKNOWN_ERROR;
+ return nullptr;
}
auto fd = evdevNode->getFd();
ALOGV("opened %s with fd %d", path.c_str(), fd);
- *outNode = std::static_pointer_cast<InputDeviceNode>(evdevNode);
- mDeviceNodes[fd] = *outNode;
+ mDeviceNodes[fd] = evdevNode;
struct epoll_event eventItem{};
eventItem.events = EPOLLIN;
if (mWakeupMechanism == WakeMechanism::EPOLL_WAKEUP) {
@@ -743,7 +770,7 @@
eventItem.data.u32 = fd;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
- return -errno;
+ return nullptr;
}
if (mNeedToCheckSuspendBlockIoctl) {
@@ -765,12 +792,12 @@
mNeedToCheckSuspendBlockIoctl = false;
}
- return OK;
+ return evdevNode;
}
-status_t InputHub::closeNode(const std::shared_ptr<InputDeviceNode>& node) {
+status_t InputHub::closeNode(const InputDeviceNode* node) {
for (auto pair : mDeviceNodes) {
- if (pair.second.get() == node.get()) {
+ if (pair.second.get() == node) {
return closeNodeByFd(pair.first);
}
}
diff --git a/modules/input/evdev/InputHub.h b/modules/input/evdev/InputHub.h
index bec327a..1abdc09 100644
--- a/modules/input/evdev/InputHub.h
+++ b/modules/input/evdev/InputHub.h
@@ -56,29 +56,55 @@
*/
class InputDeviceNode {
public:
+ /** Get the Linux device path for the node. */
virtual const std::string& getPath() const = 0;
+ /** Get the name of the device returned by the driver. */
virtual const std::string& getName() const = 0;
+ /** Get the location of the device returned by the driver. */
virtual const std::string& getLocation() const = 0;
+ /** Get the unique id of the device returned by the driver. */
virtual const std::string& getUniqueId() const = 0;
+ /** Get the bus type of the device returned by the driver. */
virtual uint16_t getBusType() const = 0;
+ /** Get the vendor id of the device returned by the driver. */
virtual uint16_t getVendorId() const = 0;
+ /** Get the product id of the device returned by the driver. */
virtual uint16_t getProductId() const = 0;
+ /** Get the version of the device driver. */
virtual uint16_t getVersion() const = 0;
+ /** Returns true if the device has the key. */
virtual bool hasKey(int32_t key) const = 0;
- virtual bool hasRelativeAxis(int axis) const = 0;
- virtual const AbsoluteAxisInfo* getAbsoluteAxisInfo(int32_t axis) const = 0;
+ /** Returns true if the device has a key in the range [startKey, endKey). */
+ virtual bool hasKeyInRange(int32_t startKey, int32_t endKey) const = 0;
+ /** Returns true if the device has the relative axis. */
+ virtual bool hasRelativeAxis(int32_t axis) const = 0;
+ /** Returns true if the device has the absolute axis. */
+ virtual bool hasAbsoluteAxis(int32_t axis) const = 0;
+ /** Returns true if the device has the switch. */
+ virtual bool hasSwitch(int32_t sw) const = 0;
+ /** Returns true if the device has the force feedback method. */
+ virtual bool hasForceFeedback(int32_t ff) const = 0;
+ /** Returns true if the device has the input property. */
virtual bool hasInputProperty(int property) const = 0;
+ /** Returns the state of the key. */
virtual int32_t getKeyState(int32_t key) const = 0;
+ /** Returns the state of the switch. */
virtual int32_t getSwitchState(int32_t sw) const = 0;
+ /** Returns information about the absolute axis. */
+ virtual const AbsoluteAxisInfo* getAbsoluteAxisInfo(int32_t axis) const = 0;
+ /** Returns the value of the absolute axis. */
virtual status_t getAbsoluteAxisValue(int32_t axis, int32_t* outValue) const = 0;
+ /** Vibrate the device for duration ns. */
virtual void vibrate(nsecs_t duration) = 0;
- virtual void cancelVibrate(int32_t deviceId) = 0;
+ /** Stop vibration on the device. */
+ virtual void cancelVibrate() = 0;
+ /** Disable key repeat for the device in the driver. */
virtual void disableDriverKeyRepeat() = 0;
protected:
@@ -89,10 +115,10 @@
/** Callback interface for receiving input events, including device changes. */
class InputCallbackInterface {
public:
- virtual void onInputEvent(std::shared_ptr<InputDeviceNode> node, InputEvent& event,
+ virtual void onInputEvent(const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
nsecs_t event_time) = 0;
- virtual void onDeviceAdded(std::shared_ptr<InputDeviceNode> node) = 0;
- virtual void onDeviceRemoved(std::shared_ptr<InputDeviceNode> node) = 0;
+ virtual void onDeviceAdded(const std::shared_ptr<InputDeviceNode>& node) = 0;
+ virtual void onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) = 0;
protected:
InputCallbackInterface() = default;
@@ -129,7 +155,7 @@
*/
class InputHub : public InputHubInterface {
public:
- explicit InputHub(std::shared_ptr<InputCallbackInterface> cb);
+ explicit InputHub(const std::shared_ptr<InputCallbackInterface>& cb);
virtual ~InputHub() override;
virtual status_t registerDevicePath(const std::string& path) override;
@@ -143,8 +169,8 @@
private:
status_t readNotify();
status_t scanDir(const std::string& path);
- status_t openNode(const std::string& path, std::shared_ptr<InputDeviceNode>* outNode);
- status_t closeNode(const std::shared_ptr<InputDeviceNode>& node);
+ std::shared_ptr<InputDeviceNode> openNode(const std::string& path);
+ status_t closeNode(const InputDeviceNode* node);
status_t closeNodeByFd(int fd);
std::shared_ptr<InputDeviceNode> findNodeByPath(const std::string& path);
diff --git a/modules/input/evdev/InputMapper.cpp b/modules/input/evdev/InputMapper.cpp
new file mode 100644
index 0000000..3893125
--- /dev/null
+++ b/modules/input/evdev/InputMapper.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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 "InputMapper.h"
+
+#include "InputHost.h"
+
+namespace android {
+
+InputReport* InputMapper::getInputReport() {
+ if (mReport) return mReport;
+ if (mInputReportDef == nullptr) return nullptr;
+ mReport = mInputReportDef->allocateReport();
+ return mReport;
+}
+
+} // namespace android
diff --git a/modules/input/evdev/InputMapper.h b/modules/input/evdev/InputMapper.h
new file mode 100644
index 0000000..5e88d06
--- /dev/null
+++ b/modules/input/evdev/InputMapper.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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_INPUT_MAPPER_H_
+#define ANDROID_INPUT_MAPPER_H_
+
+struct input_device_handle;
+
+namespace android {
+
+class InputDeviceNode;
+class InputReport;
+class InputReportDefinition;
+struct InputEvent;
+using InputDeviceHandle = struct input_device_handle;
+
+/**
+ * An InputMapper processes raw evdev input events and combines them into
+ * Android input HAL reports. A given InputMapper will focus on a particular
+ * type of input, like key presses or touch events. A single InputDevice may
+ * have multiple InputMappers, corresponding to the different types of inputs it
+ * supports.
+ */
+class InputMapper {
+public:
+ InputMapper() = default;
+ virtual ~InputMapper() {}
+
+ /**
+ * If the mapper supports input events from the InputDevice,
+ * configureInputReport will populate the InputReportDefinition and return
+ * true. If input is not supported, false is returned, and the InputDevice
+ * may free or re-use the InputReportDefinition.
+ */
+ virtual bool configureInputReport(InputDeviceNode* devNode, InputReportDefinition* report) {
+ return false;
+ }
+
+ /**
+ * If the mapper supports output events from the InputDevice,
+ * configureOutputReport will populate the InputReportDefinition and return
+ * true. If output is not supported, false is returned, and the InputDevice
+ * may free or re-use the InputReportDefinition.
+ */
+ virtual bool configureOutputReport(InputDeviceNode* devNode, InputReportDefinition* report) {
+ return false;
+ }
+
+ // Set the InputDeviceHandle after registering the device with the host.
+ virtual void setDeviceHandle(InputDeviceHandle* handle) { mDeviceHandle = handle; }
+ // Process the InputEvent.
+ virtual void process(const InputEvent& event) = 0;
+
+protected:
+ virtual void setInputReportDefinition(InputReportDefinition* reportDef) final {
+ mInputReportDef = reportDef;
+ }
+ virtual void setOutputReportDefinition(InputReportDefinition* reportDef) final {
+ mOutputReportDef = reportDef;
+ }
+ virtual InputReportDefinition* getInputReportDefinition() final { return mInputReportDef; }
+ virtual InputReportDefinition* getOutputReportDefinition() final { return mOutputReportDef; }
+ virtual InputDeviceHandle* getDeviceHandle() final { return mDeviceHandle; }
+ virtual InputReport* getInputReport() final;
+
+private:
+ InputReportDefinition* mInputReportDef = nullptr;
+ InputReportDefinition* mOutputReportDef = nullptr;
+ InputDeviceHandle* mDeviceHandle = nullptr;
+ InputReport* mReport = nullptr;
+};
+
+} // namespace android
+
+#endif // ANDROID_INPUT_MAPPER_H_
diff --git a/modules/input/evdev/MouseInputMapper.cpp b/modules/input/evdev/MouseInputMapper.cpp
new file mode 100644
index 0000000..8fba5ca
--- /dev/null
+++ b/modules/input/evdev/MouseInputMapper.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2015 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 "MouseInputMapper"
+//#define LOG_NDEBUG 0
+
+#include "MouseInputMapper.h"
+
+#include <linux/input.h>
+#include <hardware/input.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "InputHost.h"
+#include "InputHub.h"
+
+
+namespace android {
+
+// Map scancodes to input HAL usages.
+// The order of these definitions MUST remain in sync with the order they are
+// defined in linux/input.h.
+static struct {
+ int32_t scancode;
+ InputUsage usage;
+} codeMap[] = {
+ {BTN_LEFT, INPUT_USAGE_BUTTON_PRIMARY},
+ {BTN_RIGHT, INPUT_USAGE_BUTTON_SECONDARY},
+ {BTN_MIDDLE, INPUT_USAGE_BUTTON_TERTIARY},
+ {BTN_SIDE, INPUT_USAGE_BUTTON_UNKNOWN},
+ {BTN_EXTRA, INPUT_USAGE_BUTTON_UNKNOWN},
+ {BTN_FORWARD, INPUT_USAGE_BUTTON_FORWARD},
+ {BTN_BACK, INPUT_USAGE_BUTTON_BACK},
+ {BTN_TASK, INPUT_USAGE_BUTTON_UNKNOWN},
+};
+
+
+bool MouseInputMapper::configureInputReport(InputDeviceNode* devNode,
+ InputReportDefinition* report) {
+ setInputReportDefinition(report);
+ getInputReportDefinition()->addCollection(INPUT_COLLECTION_ID_MOUSE, 1);
+
+ // Configure mouse axes
+ if (!devNode->hasRelativeAxis(REL_X) || !devNode->hasRelativeAxis(REL_Y)) {
+ ALOGE("Device %s is missing a relative x or y axis. Device cannot be configured.",
+ devNode->getPath().c_str());
+ return false;
+ }
+ getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_X,
+ INT32_MIN, INT32_MAX, 1.0f);
+ getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_Y,
+ INT32_MIN, INT32_MAX, 1.0f);
+ if (devNode->hasRelativeAxis(REL_WHEEL)) {
+ getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE,
+ INPUT_USAGE_AXIS_VSCROLL, -1, 1, 0.0f);
+ }
+ if (devNode->hasRelativeAxis(REL_HWHEEL)) {
+ getInputReportDefinition()->declareUsage(INPUT_COLLECTION_ID_MOUSE,
+ INPUT_USAGE_AXIS_HSCROLL, -1, 1, 0.0f);
+ }
+
+ // Configure mouse buttons
+ InputUsage usages[NELEM(codeMap)];
+ int numUsages = 0;
+ for (int32_t i = 0; i < NELEM(codeMap); ++i) {
+ if (devNode->hasKey(codeMap[i].scancode)) {
+ usages[numUsages++] = codeMap[i].usage;
+ }
+ }
+ if (numUsages == 0) {
+ ALOGW("MouseInputMapper found no buttons for %s", devNode->getPath().c_str());
+ }
+ getInputReportDefinition()->declareUsages(INPUT_COLLECTION_ID_MOUSE, usages, numUsages);
+ return true;
+}
+
+void MouseInputMapper::process(const InputEvent& event) {
+ ALOGV("processing mouse event. type=%d code=%d value=%d",
+ event.type, event.code, event.value);
+ switch (event.type) {
+ case EV_KEY:
+ processButton(event.code, event.value);
+ break;
+ case EV_REL:
+ processMotion(event.code, event.value);
+ break;
+ case EV_SYN:
+ if (event.code == SYN_REPORT) {
+ sync(event.when);
+ }
+ break;
+ default:
+ ALOGV("unknown mouse event type: %d", event.type);
+ }
+}
+
+void MouseInputMapper::processMotion(int32_t code, int32_t value) {
+ switch (code) {
+ case REL_X:
+ mRelX = value;
+ break;
+ case REL_Y:
+ mRelY = value;
+ break;
+ case REL_WHEEL:
+ mRelWheel = value;
+ break;
+ case REL_HWHEEL:
+ mRelHWheel = value;
+ break;
+ default:
+ // Unknown code. Ignore.
+ break;
+ }
+}
+
+// Map evdev button codes to bit indices. This function assumes code >=
+// BTN_MOUSE.
+uint32_t buttonToBit(int32_t code) {
+ return static_cast<uint32_t>(code - BTN_MOUSE);
+}
+
+void MouseInputMapper::processButton(int32_t code, int32_t value) {
+ // Mouse buttons start at BTN_MOUSE and end before BTN_JOYSTICK. There isn't
+ // really enough room after the mouse buttons for another button class, so
+ // the risk of a button type being inserted after mouse is low.
+ if (code >= BTN_MOUSE && code < BTN_JOYSTICK) {
+ if (value) {
+ mButtonValues.markBit(buttonToBit(code));
+ } else {
+ mButtonValues.clearBit(buttonToBit(code));
+ }
+ mUpdatedButtonMask.markBit(buttonToBit(code));
+ }
+}
+
+void MouseInputMapper::sync(nsecs_t when) {
+ // Process updated button states.
+ while (!mUpdatedButtonMask.isEmpty()) {
+ auto bit = mUpdatedButtonMask.clearFirstMarkedBit();
+ getInputReport()->setBoolUsage(INPUT_COLLECTION_ID_MOUSE, codeMap[bit].usage,
+ mButtonValues.hasBit(bit), 0);
+ }
+
+ // Process motion and scroll changes.
+ if (mRelX != 0) {
+ getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_X, mRelX, 0);
+ }
+ if (mRelY != 0) {
+ getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_Y, mRelY, 0);
+ }
+ if (mRelWheel != 0) {
+ getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_VSCROLL,
+ mRelWheel, 0);
+ }
+ if (mRelHWheel != 0) {
+ getInputReport()->setIntUsage(INPUT_COLLECTION_ID_MOUSE, INPUT_USAGE_AXIS_HSCROLL,
+ mRelHWheel, 0);
+ }
+
+ // Report and reset.
+ getInputReport()->reportEvent(getDeviceHandle());
+ mUpdatedButtonMask.clear();
+ mButtonValues.clear();
+ mRelX = 0;
+ mRelY = 0;
+ mRelWheel = 0;
+ mRelHWheel = 0;
+}
+
+} // namespace android
diff --git a/modules/input/evdev/MouseInputMapper.h b/modules/input/evdev/MouseInputMapper.h
new file mode 100644
index 0000000..1f8bc06
--- /dev/null
+++ b/modules/input/evdev/MouseInputMapper.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 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_MOUSE_INPUT_MAPPER_H_
+#define ANDROID_MOUSE_INPUT_MAPPER_H_
+
+#include <cstdint>
+
+#include <utils/BitSet.h>
+#include <utils/Timers.h>
+
+#include "InputMapper.h"
+
+namespace android {
+
+class MouseInputMapper : public InputMapper {
+public:
+ virtual ~MouseInputMapper() = default;
+
+ virtual bool configureInputReport(InputDeviceNode* devNode,
+ InputReportDefinition* report) override;
+ virtual void process(const InputEvent& event) override;
+
+private:
+ void processMotion(int32_t code, int32_t value);
+ void processButton(int32_t code, int32_t value);
+ void sync(nsecs_t when);
+
+ BitSet32 mButtonValues;
+ BitSet32 mUpdatedButtonMask;
+
+ int32_t mRelX = 0;
+ int32_t mRelY = 0;
+
+ bool mHaveRelWheel = false;
+ bool mHaveRelHWheel = false;
+ int32_t mRelWheel = 0;
+ int32_t mRelHWheel = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_MOUSE_INPUT_MAPPER_H_
diff --git a/modules/input/evdev/SwitchInputMapper.cpp b/modules/input/evdev/SwitchInputMapper.cpp
new file mode 100644
index 0000000..bb79d01
--- /dev/null
+++ b/modules/input/evdev/SwitchInputMapper.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 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 "SwitchInputMapper"
+//#define LOG_NDEBUG 0
+
+#include "SwitchInputMapper.h"
+
+#include <inttypes.h>
+#include <linux/input.h>
+#include <hardware/input.h>
+#include <utils/Log.h>
+
+#include "InputHost.h"
+#include "InputHub.h"
+
+namespace android {
+
+static struct {
+ int32_t scancode;
+ InputUsage usage;
+} codeMap[] = {
+ {SW_LID, INPUT_USAGE_SWITCH_LID},
+ {SW_TABLET_MODE, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_HEADPHONE_INSERT, INPUT_USAGE_SWITCH_HEADPHONE_INSERT},
+ {SW_RFKILL_ALL, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_MICROPHONE_INSERT, INPUT_USAGE_SWITCH_MICROPHONE_INSERT},
+ {SW_DOCK, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_LINEOUT_INSERT, INPUT_USAGE_SWITCH_LINEOUT_INSERT},
+ {SW_JACK_PHYSICAL_INSERT, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_VIDEOOUT_INSERT, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_CAMERA_LENS_COVER, INPUT_USAGE_SWITCH_CAMERA_LENS_COVER},
+ {SW_KEYPAD_SLIDE, INPUT_USAGE_SWITCH_KEYPAD_SLIDE},
+ {SW_FRONT_PROXIMITY, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_ROTATE_LOCK, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_LINEIN_INSERT, INPUT_USAGE_SWITCH_UNKNOWN},
+ {0x0e /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
+ {SW_MAX, INPUT_USAGE_SWITCH_UNKNOWN},
+};
+
+SwitchInputMapper::SwitchInputMapper()
+ : InputMapper() {
+ static_assert(SW_CNT <= 32, "More than 32 switches defined in linux/input.h");
+}
+
+bool SwitchInputMapper::configureInputReport(InputDeviceNode* devNode,
+ InputReportDefinition* report) {
+ InputUsage usages[SW_CNT];
+ int numUsages = 0;
+ for (int32_t i = 0; i < SW_CNT; ++i) {
+ if (devNode->hasSwitch(codeMap[i].scancode)) {
+ usages[numUsages++] = codeMap[i].usage;
+ }
+ }
+ if (numUsages == 0) {
+ ALOGE("SwitchInputMapper found no switches for %s!", devNode->getPath().c_str());
+ return false;
+ }
+ setInputReportDefinition(report);
+ getInputReportDefinition()->addCollection(INPUT_COLLECTION_ID_SWITCH, 1);
+ getInputReportDefinition()->declareUsages(INPUT_COLLECTION_ID_SWITCH, usages, numUsages);
+ return true;
+}
+
+void SwitchInputMapper::process(const InputEvent& event) {
+ switch (event.type) {
+ case EV_SW:
+ processSwitch(event.code, event.value);
+ break;
+ case EV_SYN:
+ if (event.code == SYN_REPORT) {
+ sync(event.when);
+ }
+ break;
+ default:
+ ALOGV("unknown switch event type: %d", event.type);
+ }
+}
+
+void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
+ ALOGV("processing switch event. code=%" PRId32 ", value=%" PRId32, switchCode, switchValue);
+ if (switchCode >= 0 && switchCode < SW_CNT) {
+ if (switchValue) {
+ mSwitchValues.markBit(switchCode);
+ } else {
+ mSwitchValues.clearBit(switchCode);
+ }
+ mUpdatedSwitchMask.markBit(switchCode);
+ }
+}
+
+void SwitchInputMapper::sync(nsecs_t when) {
+ if (mUpdatedSwitchMask.isEmpty()) {
+ // Clear the values just in case.
+ mSwitchValues.clear();
+ return;
+ }
+
+ while (!mUpdatedSwitchMask.isEmpty()) {
+ auto bit = mUpdatedSwitchMask.firstMarkedBit();
+ getInputReport()->setBoolUsage(INPUT_COLLECTION_ID_SWITCH, codeMap[bit].usage,
+ mSwitchValues.hasBit(bit), 0);
+ mUpdatedSwitchMask.clearBit(bit);
+ }
+ getInputReport()->reportEvent(getDeviceHandle());
+ mUpdatedSwitchMask.clear();
+ mSwitchValues.clear();
+}
+
+} // namespace android
diff --git a/modules/input/evdev/SwitchInputMapper.h b/modules/input/evdev/SwitchInputMapper.h
new file mode 100644
index 0000000..e25c3a5
--- /dev/null
+++ b/modules/input/evdev/SwitchInputMapper.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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_SWITCH_INPUT_MAPPER_H_
+#define ANDROID_SWITCH_INPUT_MAPPER_H_
+
+#include <cstdint>
+
+#include <utils/BitSet.h>
+#include <utils/Timers.h>
+
+#include "InputMapper.h"
+
+namespace android {
+
+class SwitchInputMapper : public InputMapper {
+public:
+ SwitchInputMapper();
+ virtual ~SwitchInputMapper() = default;
+
+ virtual bool configureInputReport(InputDeviceNode* devNode,
+ InputReportDefinition* report) override;
+ virtual void process(const InputEvent& event) override;
+
+private:
+ void processSwitch(int32_t switchCode, int32_t switchValue);
+ void sync(nsecs_t when);
+
+ BitSet32 mSwitchValues;
+ BitSet32 mUpdatedSwitchMask;
+};
+
+} // namespace android
+
+#endif // ANDROID_SWITCH_INPUT_MAPPER_H_
diff --git a/modules/radio/Android.mk b/modules/radio/Android.mk
index f433c85..e7647b2 100644
--- a/modules/radio/Android.mk
+++ b/modules/radio/Android.mk
@@ -25,3 +25,12 @@
LOCAL_32_BIT_ONLY := true
include $(BUILD_SHARED_LIBRARY)
+
+# Stub radio tool that can be run in native.
+include $(CLEAR_VARS)
+LOCAL_MODULE := radio_hal_tool
+LOCAL_SRC_FILES := radio_hal_tool.c
+LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
+LOCAL_SHARED_LIBRARIES := libcutils libhardware liblog libradio_metadata
+
+include $(BUILD_EXECUTABLE)
diff --git a/modules/radio/radio_hal_tool.c b/modules/radio/radio_hal_tool.c
new file mode 100644
index 0000000..f5c7637
--- /dev/null
+++ b/modules/radio/radio_hal_tool.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2015 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 "radio_hal_tool"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <hardware/hardware.h>
+#include <hardware/radio.h>
+#include <system/radio.h>
+#include <system/radio_metadata.h>
+
+
+// Global state variables.
+const struct radio_tuner *hal_tuner = NULL;
+
+void usage() {
+ printf("Usage: "
+ "./radio_hal_tool -l\n"
+ "-l: List properties global to the Radio.\n"
+ );
+}
+
+void list_all_properties(radio_hw_device_t *device) {
+ radio_hal_properties_t hal_properties;
+ device->get_properties(device, &hal_properties);
+ printf("Class: %d\n"
+ "Impl: %s\n"
+ "Tuners: %d\n"
+ "Bands: %d\n\n",
+ hal_properties.class_id, hal_properties.implementor, hal_properties.num_tuners,
+ hal_properties.num_bands);
+
+ uint32_t i;
+ for (i = 0; i < hal_properties.num_bands; i++) {
+ printf("Band Information\n"
+ "Type: %d\n"
+ "Connected: %d\n"
+ "Lower limit: %d\n"
+ "Upper limit: %d\n"
+ "Spacing: %d\n\n",
+ hal_properties.bands[i].type,
+ hal_properties.bands[i].antenna_connected,
+ hal_properties.bands[i].lower_limit,
+ hal_properties.bands[i].upper_limit,
+ hal_properties.bands[i].num_spacings);
+ }
+}
+
+void callback(radio_hal_event_t *event, void *cookie) {
+ printf("\nEvent detected\n"
+ "Type: %d\n", event->type);
+}
+
+void tune(radio_hw_device_t *device, int band_number) {
+ int ret;
+ radio_hal_properties_t hal_properties;
+ ret = device->get_properties(device, &hal_properties);
+ if (ret != 0) {
+ printf("Err: get_properties returned: %d\n", ret);
+ return;
+ }
+
+ if ((uint32_t) band_number >= hal_properties.num_bands) {
+ printf("Tuner number range should be: [0, %d]\n", hal_properties.num_bands);
+ }
+ printf("Setting band config as:\n"
+ "Type: %d\n"
+ "Connected: %d\n"
+ "Lower limit: %d\n"
+ "Upper limit: %d\n"
+ "Spacing: %d\n\n",
+ hal_properties.bands[band_number].type,
+ hal_properties.bands[band_number].antenna_connected,
+ hal_properties.bands[band_number].lower_limit,
+ hal_properties.bands[band_number].upper_limit,
+ hal_properties.bands[band_number].num_spacings);
+ int cookie = 0;
+ ret = device->open_tuner(
+ device, (const radio_hal_band_config_t *) (&(hal_properties.bands[band_number])), false,
+ callback, &cookie, &hal_tuner);
+ if (ret != 0) {
+ printf("Err: open_tuner returned: %d\n", ret);
+ return;
+ }
+ // It takes some time to apply the config which is currently set as 500ms in
+ // the stub implementation.
+ sleep(1);
+
+ // Stub tuner implementation will regard this magic channel as a valid channel to tune.
+ ret = hal_tuner->tune(hal_tuner, 87916, 0);
+ if (ret != 0) {
+ printf("Err: tune returned: %d\n", ret);
+ return;
+ }
+ // In the stub implementation it takes ~100ms to tune to the channel and the
+ // data is set rightafter.
+ sleep(1);
+}
+
+void get_tuner_metadata(radio_hw_device_t *device) {
+ // Get the metadata and print it.
+ radio_program_info_t info;
+ radio_metadata_allocate(&info.metadata, 87916, 0);
+ int ret;
+ ret = hal_tuner->get_program_information(hal_tuner, &info);
+ if (ret != 0) {
+ printf("Err: Get program info ret code: %d\n", ret);
+ return;
+ }
+
+ // Print the info.
+ printf("Metadata from the band\n");
+ int i;
+ for (i = 0; i < radio_metadata_get_count(info.metadata); i++) {
+ radio_metadata_key_t key;
+ radio_metadata_type_t type;
+ void *value;
+ uint32_t size;
+
+ radio_metadata_get_at_index(info.metadata, i, &key, &type, &value, &size);
+
+ printf("\nMetadata key: %d\n"
+ "Type: %d\n", key, type);
+
+ switch (type) {
+ case RADIO_METADATA_TYPE_INT:
+ printf("Int value: %d\n", *((int *) value));
+ break;
+ case RADIO_METADATA_TYPE_TEXT:
+ printf("Text value: %s\n", (char *) value);
+ break;
+ case RADIO_METADATA_TYPE_RAW:
+ printf("Raw value, skipping\n");
+ break;
+ case RADIO_METADATA_TYPE_CLOCK:
+ printf("UTC Epoch: %lld\n"
+ "UTC Offset: %d\n",
+ ((radio_metadata_clock_t *) value)->utc_seconds_since_epoch,
+ ((radio_metadata_clock_t *) value)->timezone_offset_in_minutes);
+ }
+ }
+
+ // Close the tuner when we are done.
+ ret = device->close_tuner(device, hal_tuner);
+ if (ret != 0) {
+ printf("Err: close_tuner returned: %d\n", ret);
+ }
+}
+
+int main(int argc, char** argv) {
+ // Open the radio module and just ask for the list of properties.
+ const hw_module_t *hw_module = NULL;
+ int rc;
+ rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, RADIO_HARDWARE_MODULE_ID_FM, &hw_module);
+ if (rc != 0) {
+ printf("Cannot open the hw module. Does the HAL exist? %d\n", rc);
+ return -1;
+ }
+
+ radio_hw_device_t *dev;
+ rc = radio_hw_device_open(hw_module, &dev);
+ if (rc != 0) {
+ printf("Cannot open the device. Check that HAL implementation. %d\n", rc);
+ return -1;
+ }
+ printf("HAL Loaded!\n");
+
+ // If this is a list properties command - we check for -l command.
+ int list_properties = 0;
+ // Get metadata.
+ int get_metadata = 0;
+ // Tune. Takes a tuner number (see bands obtainaed by list_properties).
+ int should_tune = 0;
+ int band_number = -1;
+
+ int opt;
+ while ((opt = getopt(argc, argv, "lmt:")) != -1) {
+ switch (opt) {
+ case 'l':
+ list_properties = 1;
+ break;
+ case 't':
+ should_tune = 1;
+ band_number = atoi(optarg);
+ break;
+ case 'm':
+ get_metadata = 1;
+ break;
+ }
+ }
+
+ if (list_properties) {
+ printf("Listing properties...\n");
+ list_all_properties(dev);
+ } else {
+ if (should_tune) {
+ if (band_number < 0) {
+ printf("Tuner number should be positive");
+ return -1;
+ }
+ printf("Tuning to a station...\n");
+ tune(dev, band_number);
+ }
+ if (get_metadata) {
+ if (!hal_tuner) {
+ printf("Please pass -t <band_number> to tune to a valid station to get metadata.");
+ exit(1);
+ }
+ get_tuner_metadata(dev);
+ }
+ }
+ return 0;
+}
diff --git a/modules/radio/radio_hw.c b/modules/radio/radio_hw.c
index 9c0f22c..bd9e324 100644
--- a/modules/radio/radio_hw.c
+++ b/modules/radio/radio_hw.c
@@ -58,6 +58,7 @@
.rds = RADIO_RDS_US,
.ta = false,
.af = false,
+ .ea = true,
}
},
{
@@ -74,6 +75,11 @@
}
};
+static const radio_metadata_clock_t hw_clock = {
+ .utc_seconds_since_epoch = 1234567890,
+ .timezone_offset_in_minutes = (-8 * 60),
+};
+
struct stub_radio_tuner {
struct radio_tuner interface;
struct stub_radio_device *dev;
@@ -103,6 +109,7 @@
CMD_TUNE,
CMD_CANCEL,
CMD_METADATA,
+ CMD_ANNOUNCEMENTS,
} thread_cmd_type_t;
struct thread_command {
@@ -215,6 +222,9 @@
ret = add_bitmap_metadata(metadata, RADIO_METADATA_KEY_ICON, BITMAP_FILE_PATH);
if (ret != 0)
goto exit;
+ ret = radio_metadata_add_clock(metadata, RADIO_METADATA_KEY_CLOCK, &hw_clock);
+ if (ret != 0)
+ goto exit;
} else {
ret = add_bitmap_metadata(metadata, RADIO_METADATA_KEY_ART, BITMAP_FILE_PATH);
if (ret != 0)
@@ -251,6 +261,10 @@
pthread_mutex_lock(&tuner->lock);
+ // Fields which are used to toggle the state of traffic announcements and
+ // ea announcements at random. They are access protected by tuner->lock.
+ bool ea_state = false;
+
while (true) {
struct thread_command *cmd = NULL;
struct listnode *item;
@@ -278,7 +292,8 @@
cmd = node_to_item(item, struct thread_command, node);
if (got_cancel && (cmd->type == CMD_STEP || cmd->type == CMD_SCAN ||
- cmd->type == CMD_TUNE || cmd->type == CMD_METADATA)) {
+ cmd->type == CMD_TUNE || cmd->type == CMD_METADATA ||
+ cmd->type == CMD_ANNOUNCEMENTS)) {
list_remove(item);
free(cmd);
continue;
@@ -309,9 +324,11 @@
__func__, tuner->config.type,
tuner->config.lower_limit, tuner->config.upper_limit);
if (tuner->config.type == RADIO_BAND_FM) {
- ALOGV(" - stereo %d\n - rds %d\n - ta %d\n - af %d",
+ ALOGV(" - stereo %d\n - rds %d\n - ta %d\n - af %d\n"
+ " - ea %d\n",
tuner->config.fm.stereo, tuner->config.fm.rds,
- tuner->config.fm.ta, tuner->config.fm.af);
+ tuner->config.fm.ta, tuner->config.fm.af,
+ tuner->config.fm.ea);
} else {
ALOGV(" - stereo %d", tuner->config.am.stereo);
}
@@ -377,7 +394,7 @@
if (tuner->program.tuned) {
prepare_metadata(tuner, &tuner->program.metadata, true);
- send_command_l(tuner, CMD_METADATA, 5000, NULL);
+ send_command_l(tuner, CMD_ANNOUNCEMENTS, 1000, NULL);
} else {
if (tuner->program.metadata != NULL)
radio_metadata_deallocate(tuner->program.metadata);
@@ -408,6 +425,28 @@
got_cancel = true;
} break;
+ // Fire emergency announcements if they are enabled in the config. Stub
+ // implementation simply fires an announcement for 5 second
+ // duration with a gap of 5 seconds.
+ case CMD_ANNOUNCEMENTS: {
+ ALOGV("In annoucements. %d %d %d\n",
+ ea_state, tuner->config.type, tuner->config.fm.ea);
+ if (tuner->config.type == RADIO_BAND_FM ||
+ tuner->config.type == RADIO_BAND_FM_HD) {
+ if (ea_state) {
+ ea_state = false;
+ event.type = RADIO_EVENT_EA;
+ } else if (tuner->config.fm.ea) {
+ ea_state = true;
+ event.type = RADIO_EVENT_EA;
+ }
+ event.on = ea_state;
+
+ if (tuner->config.fm.ea) {
+ send_command_l(tuner, CMD_ANNOUNCEMENTS, 5000, NULL);
+ }
+ }
+ } break;
}
if (event.type != RADIO_EVENT_HW_FAILURE && tuner->callback != NULL) {
pthread_mutex_unlock(&tuner->lock);
@@ -438,7 +477,7 @@
free(cmd);
}
}
- send_command_l(tuner, CMD_METADATA, 100, NULL);
+ send_command_l(tuner, CMD_METADATA, 1000, NULL);
}
}
@@ -472,7 +511,7 @@
}
static int tuner_get_configuration(const struct radio_tuner *tuner,
- radio_hal_band_config_t *config)
+ radio_hal_band_config_t *config)
{
struct stub_radio_tuner *stub_tuner = (struct stub_radio_tuner *)tuner;
int status = 0;
diff --git a/modules/soundtrigger/sound_trigger_hw.c b/modules/soundtrigger/sound_trigger_hw.c
index e7f9baf..8dba27a 100644
--- a/modules/soundtrigger/sound_trigger_hw.c
+++ b/modules/soundtrigger/sound_trigger_hw.c
@@ -14,10 +14,37 @@
* limitations under the License.
*/
+
+/* This HAL simulates triggers from the DSP.
+ * To send a trigger from the command line you can type:
+ *
+ * adb forward tcp:14035 tcp:14035
+ * echo $'\001' | nc -q -1 localhost 14035
+ *
+ * $'\001' corresponds to the index_position of loaded sound
+ * model, you can also send $'\002' etc. $'\000' is the kill
+ * signal for the trigger listening thread.
+ *
+ * To enable this file, you must change the src file in this
+ * directory's Android.mk file, then change the sound_trigger
+ * product package in the device-specific device.mk file,
+ * for example, in device/htc/flounder
+ */
+
#define LOG_TAG "sound_trigger_hw_default"
/*#define LOG_NDEBUG 0*/
#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <errno.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <cutils/log.h>
@@ -26,12 +53,16 @@
#include <system/sound_trigger.h>
#include <hardware/sound_trigger.h>
+/* Although max_sound_models is specified in sound_trigger_properties, having a maximum maximum
+allows a dramatic simplification of data structures in this file */
+#define MAX_MAX_SOUND_MODELS 5
+
static const struct sound_trigger_properties hw_properties = {
"The Android Open Source Project", // implementor
"Sound Trigger stub HAL", // description
1, // version
{ 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
- 1, // max_sound_models
+ 2, // max_sound_models
1, // max_key_phrases
1, // max_users
RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
@@ -42,68 +73,207 @@
0 // power_consumption_mw
};
-struct stub_sound_trigger_device {
- struct sound_trigger_hw_device device;
- sound_model_handle_t model_handle;
- recognition_callback_t recognition_callback;
- void *recognition_cookie;
+struct recognition_context {
+ /* Sound Model Information Modified On Load */
+ sound_model_handle_t loaded_sound_model;
sound_model_callback_t sound_model_callback;
void *sound_model_cookie;
- pthread_t callback_thread;
+
+ /* Sound Model Information Modified On Recognition Start */
+ struct sound_trigger_recognition_config *config;
+ recognition_callback_t recognition_callback;
+ void *recognition_cookie;
+}
+
+struct stub_sound_trigger_device {
+ struct sound_trigger_hw_device device;
pthread_mutex_t lock;
- pthread_cond_t cond;
+ pthread_t callback_thread;
+
+ struct recognition_context re_context[MAX_MAX_SOUND_MODELS];
+
+ int next_sound_model_id;
};
+/* Will reuse ids when overflow occurs */
+static unsigned int generate_sound_model_id(const struct sound_trigger_hw_device *dev) {
+ struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
+ int new_id = stdev->next_sound_model_id;
+ ++stdev->next_sound_model_id;
+ if (stdev->next_sound_model_id == 0) {
+ stdev->next_sound_model_id = 1;
+ }
+ return new_id;
+}
-static void *callback_thread_loop(void *context)
-{
+static char *sound_trigger_event_alloc(struct stub_sound_trigger_device *stdev,
+ sound_model_handle_t handle) {
+ struct sound_trigger_phrase_recognition_event *event;
+ char *data;
+ data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event));
+ if (!data)
+ return NULL;
+
+ unsigned int model_index;
+ bool found = false;
+ for(model_index = 0; model_index < hw_properties.max_sound_models; model_index++) {
+ if (stdev->re_context[model_index]->loaded_sound_model == handle) {
+ found = true;
+ break;
+ }
+ }
+ if (found == false) {
+ ALOGW("Can't find model");
+ return NULL;
+ }
+
+ event = (struct sound_trigger_phrase_recognition_event *)data;
+ event->common.status = RECOGNITION_STATUS_SUCCESS;
+ event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
+ event->common.model = handle;
+
+ if (stdev->re_context[model_index]->config) {
+ unsigned int i;
+
+ event->num_phrases = stdev->re_context[model_index]->config->num_phrases;
+ if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
+ event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
+ for (i=0; i < event->num_phrases; i++)
+ memcpy(&event->phrase_extras[i], &stdev->re_context[model_index]->config->phrases[i],
+ sizeof(struct sound_trigger_phrase_recognition_extra));
+ }
+
+ event->num_phrases = 1;
+ event->phrase_extras[0].confidence_level = 100;
+ event->phrase_extras[0].num_levels = 1;
+ event->phrase_extras[0].levels[0].level = 100;
+ event->phrase_extras[0].levels[0].user_id = 0;
+ // Signify that all the data is comming through streaming, not through the buffer.
+ event->common.capture_available = true;
+
+ event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
+ event->common.audio_config.sample_rate = 16000;
+ event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
+ event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
+
+ return data;
+}
+
+static void *callback_thread_loop(void *context) {
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context;
- ALOGI("%s", __func__);
+ struct sockaddr_in incoming_info;
+ struct sockaddr_in self_info;
+ int self_socket;
+ socklen_t sock_size = sizeof(struct sockaddr_in);
+ memset(&self_info, 0, sizeof(self_info));
+ self_info.sin_family = AF_INET;
+ self_info.sin_addr.s_addr = htonl(INADDR_ANY);
+ self_info.sin_port = htons(14035);
- prctl(PR_SET_NAME, (unsigned long)"sound trigger callback", 0, 0, 0);
+ bool exit = false;
+ while(!exit) {
+ int received_count;
+ int requested_count = 1;
+ char buffer[requested_count];
+ ALOGE("Opening socket");
+ self_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (self_socket < 0) {
+ ALOGE("Error on socket creation");
+ exit = true;
+ } else {
+ ALOGI("Socket created");
+ }
- pthread_mutex_lock(&stdev->lock);
- if (stdev->recognition_callback == NULL) {
- goto exit;
+ int reuse = 1;
+ if (setsockopt(self_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) {
+ ALOGE("setsockopt(SO_REUSEADDR) failed");
+ }
+
+ int bind_result = bind(self_socket, (struct sockaddr *)&self_info, sizeof(struct sockaddr));
+ if (bind_result < 0) {
+ ALOGE("Error on bind");
+ exit = true;
+ }
+
+ int listen_result = listen(self_socket, 1);
+ if (listen_result < 0) {
+ ALOGE("Error on Listen");
+ exit = true;
+ }
+
+ while(!exit) {
+ int con_socket = accept(self_socket, (struct sockaddr *)&incoming_info, &sock_size);
+ if (!con_socket) {
+ ALOGE("Lost socket, cannot send trigger");
+ break;
+ }
+ ALOGI("Connection from %s", inet_ntoa(incoming_info.sin_addr));
+ received_count = recv(con_socket, buffer, requested_count, 0);
+ unsigned int index = buffer[0] - 1;
+ ALOGI("Received data");
+ pthread_mutex_lock(&stdev->lock);
+ if (received_count > 0) {
+ if (buffer[0] == 0) {
+ ALOGI("Received kill signal: stop listening to incoming server messages");
+ exit = true;
+ } else if (index < hw_properties.max_sound_models) {
+ ALOGI("Going to send trigger for model #%d", index );
+ if (stdev->re_context[index]->recognition_callback != NULL) {
+ sound_model_handle_t handle = stdev->re_context[index]->loaded_sound_model;
+ if (handle == 0) {
+ ALOGW("This trigger is not loaded");
+ } else {
+ struct sound_trigger_phrase_recognition_event *event;
+ event = (struct sound_trigger_phrase_recognition_event *)
+ sound_trigger_event_alloc(stdev, handle);
+ if (event) {
+ ALOGI("%s send callback model %d", __func__, index);
+ stdev->re_context[index]->recognition_callback(&event->common,
+ stdev->re_context[index]->recognition_cookie);
+ free(event);
+ stdev->re_context[index]->recognition_callback = NULL;
+ }
+ exit = true;
+ }
+ } else {
+ ALOGI("%s No matching callback for %d", __func__, index);
+ }
+ } else {
+ ALOGI("Data is not recognized: %d", index);
+ }
+ } else {
+ ALOGI("Received sata is size 0");
+ }
+ pthread_mutex_unlock(&stdev->lock);
+ close(con_socket);
+ }
+ ALOGE("Closing socket");
+ close(self_socket);
}
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
- ts.tv_sec += 3;
- ALOGI("%s wait 3 sec", __func__);
- int rc = pthread_cond_timedwait(&stdev->cond, &stdev->lock, &ts);
- if (rc == ETIMEDOUT && stdev->recognition_callback != NULL) {
- char *data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event) + 1);
- struct sound_trigger_phrase_recognition_event *event =
- (struct sound_trigger_phrase_recognition_event *)data;
- event->common.status = RECOGNITION_STATUS_SUCCESS;
- event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
- event->common.model = stdev->model_handle;
- event->num_phrases = 1;
- event->phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER;
- event->phrase_extras[0].confidence_level = 100;
- event->phrase_extras[0].num_levels = 1;
- event->phrase_extras[0].levels[0].level = 100;
- event->phrase_extras[0].levels[0].user_id = 0;
- event->common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
- event->common.data_size = 1;
- data[event->common.data_offset] = 8;
- ALOGI("%s send callback model %d", __func__, stdev->model_handle);
- stdev->recognition_callback(&event->common, stdev->recognition_cookie);
- free(data);
- } else {
- ALOGI("%s abort recognition model %d", __func__, stdev->model_handle);
- }
- stdev->recognition_callback = NULL;
-
-exit:
- pthread_mutex_unlock(&stdev->lock);
return NULL;
}
+static void send_loop_kill_signal() {
+ ALOGI("Sending loop thread kill signal");
+ int self_socket = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in remote_info;
+ memset(&remote_info, 0, sizeof(remote_info));
+ remote_info.sin_family = AF_INET;
+ remote_info.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ remote_info.sin_port = htons(14035);
+ if (connect(self_socket, (struct sockaddr *)&remote_info, sizeof(struct sockaddr)) == 0) {
+ char msg[] = {0};
+ send(self_socket, msg, 1, 0);
+ } else {
+ ALOGI("Could not connect");
+ }
+ close(self_socket);
+ ALOGI("Sent loop thread kill signal");
+}
+
static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
- struct sound_trigger_properties *properties)
-{
+ struct sound_trigger_properties *properties) {
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
ALOGI("%s", __func__);
@@ -117,140 +287,177 @@
struct sound_trigger_sound_model *sound_model,
sound_model_callback_t callback,
void *cookie,
- sound_model_handle_t *handle)
-{
+ sound_model_handle_t *handle) {
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
int status = 0;
ALOGI("%s stdev %p", __func__, stdev);
pthread_mutex_lock(&stdev->lock);
+
if (handle == NULL || sound_model == NULL) {
- status = -EINVAL;
- goto exit;
+ pthread_mutex_unlock(&stdev->lock);
+ return -EINVAL;
}
if (sound_model->data_size == 0 ||
sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
- status = -EINVAL;
- goto exit;
+ pthread_mutex_unlock(&stdev->lock);
+ return -EINVAL;
}
- if (stdev->model_handle == 1) {
- status = -ENOSYS;
- goto exit;
+ /* Find if there is space for this sound model */
+ unsigned int model_index;
+ bool found = false;
+ for(model_index = 0; model_index < hw_properties.max_sound_models; model_index++) {
+ if (stdev->re_context[model_index]->loaded_sound_model == 0) {
+ found = true;
+ break;
+ }
}
+ if (found == false) {
+ ALOGW("Can't load model: reached max sound model limit");
+ pthread_mutex_unlock(&stdev->lock);
+ return -ENOSYS;
+ }
+
+ stdev->re_context[model_index]->loaded_sound_model = generate_sound_model_id(dev);
+ *handle = stdev->re_context[model_index]->loaded_sound_model;
+
char *data = (char *)sound_model + sound_model->data_offset;
ALOGI("%s data size %d data %d - %d", __func__,
sound_model->data_size, data[0], data[sound_model->data_size - 1]);
- stdev->model_handle = 1;
- stdev->sound_model_callback = callback;
- stdev->sound_model_cookie = cookie;
+ stdev->re_context[model_index]->sound_model_callback = callback;
+ stdev->re_context[model_index]->sound_model_cookie = cookie;
- *handle = stdev->model_handle;
-
-exit:
pthread_mutex_unlock(&stdev->lock);
return status;
}
static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
- sound_model_handle_t handle)
-{
+ sound_model_handle_t handle) {
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
int status = 0;
-
- ALOGI("%s handle %d", __func__, handle);
+ ALOGI("unload_sound_model");
pthread_mutex_lock(&stdev->lock);
- if (handle != 1) {
- status = -EINVAL;
- goto exit;
+
+ unsigned int i;
+ unsigned int model_index;
+ bool found = false;
+ bool other_callbacks_found = false;
+ for(i = 0; i < hw_properties.max_sound_models; i++) {
+ if (stdev->re_context[i]->loaded_sound_model == handle) {
+ found = true;
+ model_index = i;
+ break;
+ } else if (stdev->re_context[i]->recognition_callback != NULL) {
+ other_callbacks_found = true;
+ }
}
- if (stdev->model_handle == 0) {
- status = -ENOSYS;
- goto exit;
- }
- stdev->model_handle = 0;
- if (stdev->recognition_callback != NULL) {
- stdev->recognition_callback = NULL;
- pthread_cond_signal(&stdev->cond);
+ if (found == false) {
+ ALOGW("Can't sound model %d in registered list", handle);
pthread_mutex_unlock(&stdev->lock);
- pthread_join(stdev->callback_thread, (void **) NULL);
- pthread_mutex_lock(&stdev->lock);
+ return -ENOSYS;
}
-exit:
- pthread_mutex_unlock(&stdev->lock);
+ stdev->re_context[i]->loaded_sound_model = 0;
+ stdev->re_context[i]->sound_model_callback = NULL;
+ stdev->re_context[i]->sound_model_cookie = NULL;
+
+ free(stdev->re_context[i]->config);
+ stdev->re_context[i]->config = NULL;
+ stdev->re_context[i]->recognition_callback = NULL;
+ stdev->re_context[i]->recognition_cookie = NULL;
+
+ /* If no more models running with callbacks, stop trigger thread */
+ if (!other_callbacks_found) {
+ send_loop_kill_signal();
+ pthread_mutex_unlock(&stdev->lock);
+ pthread_join(stdev->callback_thread, (void **)NULL);
+ } else {
+ pthread_mutex_unlock(&stdev->lock);
+ }
+
return status;
}
static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
- sound_model_handle_t sound_model_handle,
+ sound_model_handle_t handle,
const struct sound_trigger_recognition_config *config,
recognition_callback_t callback,
- void *cookie)
-{
+ void *cookie) {
+ ALOGI("%s", __func__);
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
- int status = 0;
- ALOGI("%s sound model %d", __func__, sound_model_handle);
pthread_mutex_lock(&stdev->lock);
- if (stdev->model_handle != sound_model_handle) {
- status = -ENOSYS;
- goto exit;
+ unsigned int i;
+ bool found = false;
+ for(i = 0; i < hw_properties.max_sound_models; i++) {
+ if (stdev->re_context[i]->loaded_sound_model == handle) {
+ found = true;
+ break;
+ }
}
- if (stdev->recognition_callback != NULL) {
- status = -ENOSYS;
- goto exit;
- }
- if (config->data_size != 0) {
- char *data = (char *)config + config->data_offset;
- ALOGI("%s data size %d data %d - %d", __func__,
- config->data_size, data[0], data[config->data_size - 1]);
+ if (found == false) {
+ ALOGW("Can't sound model %d in registered list", handle);
+ pthread_mutex_unlock(&stdev->lock);
+ return -ENOSYS;
}
- stdev->recognition_callback = callback;
- stdev->recognition_cookie = cookie;
+ free(stdev->re_context[i]->config);
+ stdev->re_context[i]->config = NULL;
+ if (config) {
+ stdev->re_context[i]->config = malloc(sizeof(*config));
+ if (!stdev->re_context[i]->config) {
+ pthread_mutex_unlock(&stdev->lock);
+ return -ENOMEM;
+ }
+ memcpy(stdev->re_context[i]->config, config, sizeof(*config));
+ }
+ stdev->re_context[i]->recognition_callback = callback;
+ stdev->re_context[i]->recognition_cookie = cookie;
+
pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
callback_thread_loop, stdev);
-exit:
pthread_mutex_unlock(&stdev->lock);
- return status;
+ return 0;
}
static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
- sound_model_handle_t sound_model_handle)
-{
+ sound_model_handle_t handle) {
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
- int status = 0;
- ALOGI("%s sound model %d", __func__, sound_model_handle);
+ ALOGI("%s", __func__);
pthread_mutex_lock(&stdev->lock);
- if (stdev->model_handle != sound_model_handle) {
- status = -ENOSYS;
- goto exit;
+
+ unsigned int i;
+ bool found = false;
+ for(i = 0; i < hw_properties.max_sound_models; i++) {
+ if (stdev->re_context[i]->loaded_sound_model == handle) {
+ found = true;
+ break;
+ }
}
- if (stdev->recognition_callback == NULL) {
- status = -ENOSYS;
- goto exit;
+ if (found == false) {
+ ALOGW("Can't sound model %d in registered list", handle);
+ pthread_mutex_unlock(&stdev->lock);
+ return -ENOSYS;
}
- stdev->recognition_callback = NULL;
- pthread_cond_signal(&stdev->cond);
+
+ free(stdev->re_context[i]->config);
+ stdev->re_context[i]->config = NULL;
+ stdev->re_context[i]->recognition_callback = NULL;
+ stdev->re_context[i]->recognition_cookie = NULL;
+
+ send_loop_kill_signal();
pthread_mutex_unlock(&stdev->lock);
pthread_join(stdev->callback_thread, (void **) NULL);
- pthread_mutex_lock(&stdev->lock);
-
-exit:
- pthread_mutex_unlock(&stdev->lock);
- return status;
+ return 0;
}
-
-static int stdev_close(hw_device_t *device)
-{
+static int stdev_close(hw_device_t *device) {
free(device);
return 0;
}
static int stdev_open(const hw_module_t* module, const char* name,
- hw_device_t** device)
-{
+ hw_device_t** device) {
struct stub_sound_trigger_device *stdev;
int ret;
@@ -261,6 +468,22 @@
if (!stdev)
return -ENOMEM;
+ if (MAX_MAX_SOUND_MODELS < hw_properties.max_sound_models) {
+ ALOGW("max_sound_models is greater than the allowed %d", MAX_MAX_SOUND_MODELS);
+ return -EINVAL;
+ }
+
+ stdev->next_sound_model_id = 1;
+ unsigned int i;
+ for(i = 0; i < hw_properties.max_sound_models; i++) {
+ stdev->re_context[i]->loaded_sound_model = 0;
+ stdev->re_context[i]->sound_model_callback = NULL;
+ stdev->re_context[i]->sound_model_cookie = NULL;
+ stdev->re_context[i]->config = NULL;
+ stdev->re_context[i]->recognition_callback = NULL;
+ stdev->re_context[i]->recognition_cookie = NULL;
+ }
+
stdev->device.common.tag = HARDWARE_DEVICE_TAG;
stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
stdev->device.common.module = (struct hw_module_t *) module;
@@ -272,7 +495,6 @@
stdev->device.stop_recognition = stdev_stop_recognition;
pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
- pthread_cond_init(&stdev->cond, (const pthread_condattr_t *) NULL);
*device = &stdev->device.common;
diff --git a/modules/tv_input/tv_input.cpp b/modules/tv_input/tv_input.cpp
index 114e80e..45e8388 100644
--- a/modules/tv_input/tv_input.cpp
+++ b/modules/tv_input/tv_input.cpp
@@ -37,18 +37,18 @@
const char* name, struct hw_device_t** device);
static struct hw_module_methods_t tv_input_module_methods = {
- open: tv_input_device_open
+ .open = tv_input_device_open
};
tv_input_module_t HAL_MODULE_INFO_SYM = {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 0,
- version_minor: 1,
- id: TV_INPUT_HARDWARE_MODULE_ID,
- name: "Sample TV input module",
- author: "The Android Open Source Project",
- methods: &tv_input_module_methods,
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 0,
+ .version_minor = 1,
+ .id = TV_INPUT_HARDWARE_MODULE_ID,
+ .name = "Sample TV input module",
+ .author = "The Android Open Source Project",
+ .methods = &tv_input_module_methods,
}
};
@@ -72,7 +72,8 @@
}
static int tv_input_get_stream_configurations(
- const struct tv_input_device*, int, int*, const tv_stream_config_t**)
+ const struct tv_input_device*, int, int*,
+ const tv_stream_config_t**)
{
return -EINVAL;
}
@@ -98,6 +99,13 @@
return -EINVAL;
}
+static int tv_input_get_stream_configurations_ext(
+ const struct tv_input_device*, int, int*,
+ const tv_stream_config_ext_t**)
+{
+ return -EINVAL;
+}
+
/*****************************************************************************/
static int tv_input_device_close(struct hw_device_t *dev)
@@ -134,6 +142,8 @@
dev->device.close_stream = tv_input_close_stream;
dev->device.request_capture = tv_input_request_capture;
dev->device.cancel_capture = tv_input_cancel_capture;
+ dev->device.get_stream_configurations_ext =
+ tv_input_get_stream_configurations_ext;
*device = &dev->device.common;
status = 0;
diff --git a/modules/usbaudio/audio_hal.c b/modules/usbaudio/audio_hal.c
index 38fea86..d899d6b 100644
--- a/modules/usbaudio/audio_hal.c
+++ b/modules/usbaudio/audio_hal.c
@@ -55,11 +55,6 @@
#define DEFAULT_INPUT_BUFFER_SIZE_MS 20
-// stereo channel count
-#define FCC_2 2
-// fixed channel count of 8 limitation (for data processing in AudioFlinger)
-#define FCC_8 8
-
struct audio_device {
struct audio_hw_device hw_device;
@@ -449,8 +444,6 @@
const int ret = proxy_get_presentation_position(proxy, frames, timestamp);
pthread_mutex_unlock(&out->lock);
- ALOGV("out_get_presentation_position() status:%d frames:%llu",
- ret, (unsigned long long)*frames);
return ret;
}
@@ -560,6 +553,7 @@
} else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
proposed_channel_count = profile_get_default_channel_count(out->profile);
}
+
if (proposed_channel_count != 0) {
if (proposed_channel_count <= FCC_2) {
// use channel position mask for mono and stereo
@@ -569,17 +563,17 @@
config->channel_mask =
audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
}
- out->hal_channel_count = proposed_channel_count;
} else {
- out->hal_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
+ proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
}
+ out->hal_channel_count = proposed_channel_count;
+
/* we can expose any channel mask, and emulate internally based on channel count. */
out->hal_channel_mask = config->channel_mask;
/* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
* and we emulate any channel count discrepancies in out_write(). */
- proxy_config.channels = proposed_channel_count;
-
+ proxy_config.channels = out->hal_channel_count;
proxy_prepare(&out->proxy, out->profile, &proxy_config);
/* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
diff --git a/modules/vehicle/Android.mk b/modules/vehicle/Android.mk
new file mode 100644
index 0000000..a666bc6
--- /dev/null
+++ b/modules/vehicle/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := vehicle.default
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_C_INCLUDES := hardware/libhardware
+LOCAL_SRC_FILES := vehicle.c timeUtil.cpp
+LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/modules/vehicle/timeUtil.cpp b/modules/vehicle/timeUtil.cpp
new file mode 100644
index 0000000..fb27dad
--- /dev/null
+++ b/modules/vehicle/timeUtil.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 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 <stdint.h>
+#include <utils/SystemClock.h>
+
+extern "C" {
+ int64_t elapsedRealtimeNano() {
+ return android::elapsedRealtimeNano();
+ }
+}
diff --git a/modules/vehicle/vehicle.c b/modules/vehicle/vehicle.c
new file mode 100644
index 0000000..38c38ee
--- /dev/null
+++ b/modules/vehicle/vehicle.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2015 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 "vehicle_hw_default"
+#define LOG_NDEBUG 1
+#define RADIO_PRESET_NUM 6
+
+#define UNUSED __attribute__((__unused__))
+
+#include <errno.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <cutils/log.h>
+#include <system/radio.h>
+#include <hardware/hardware.h>
+#include <hardware/vehicle.h>
+
+extern int64_t elapsedRealtimeNano();
+
+static char VEHICLE_MAKE[] = "android_car";
+
+typedef struct vehicle_device_impl {
+ vehicle_hw_device_t vehicle_device;
+ uint32_t initialized_;
+ vehicle_event_callback_fn event_fn_;
+ vehicle_error_callback_fn error_fn_;
+} vehicle_device_impl_t ;
+
+static pthread_mutex_t lock_;
+
+typedef struct subscription {
+ // Each subscription has it's own thread.
+ pthread_t thread_id;
+ int32_t prop;
+ float sample_rate;
+ pthread_mutex_t lock;
+ // This field should be protected by the above mutex.
+ // TODO change this to something better as flag alone takes long time to finish.
+ uint32_t stop_thread;
+ vehicle_device_impl_t* impl;
+ pthread_t thread;
+ pthread_cond_t cond;
+ char name[100];
+} subscription_t;
+
+static vehicle_prop_config_t CONFIGS[] = {
+ {
+ .prop = VEHICLE_PROPERTY_INFO_MAKE,
+ .access = VEHICLE_PROP_ACCESS_READ,
+ .change_mode = VEHICLE_PROP_CHANGE_MODE_STATIC,
+ .value_type = VEHICLE_VALUE_TYPE_STRING,
+ .min_sample_rate = 0,
+ .max_sample_rate = 0,
+ .hal_data = NULL,
+ },
+ {
+ .prop = VEHICLE_PROPERTY_GEAR_SELECTION,
+ .access = VEHICLE_PROP_ACCESS_READ,
+ .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+ .value_type = VEHICLE_VALUE_TYPE_INT32,
+ .min_sample_rate = 0,
+ .max_sample_rate = 0,
+ .hal_data = NULL,
+ },
+ {
+ .prop = VEHICLE_PROPERTY_DRIVING_STATUS,
+ .access = VEHICLE_PROP_ACCESS_READ,
+ .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+ .value_type = VEHICLE_VALUE_TYPE_INT32,
+ .min_sample_rate = 0,
+ .max_sample_rate = 0,
+ .hal_data = NULL,
+ },
+ {
+ .prop = VEHICLE_PROPERTY_PARKING_BRAKE_ON,
+ .access = VEHICLE_PROP_ACCESS_READ,
+ .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+ .value_type = VEHICLE_VALUE_TYPE_BOOLEAN,
+ .min_sample_rate = 0,
+ .max_sample_rate = 0,
+ .hal_data = NULL,
+ },
+ {
+ .prop = VEHICLE_PROPERTY_PERF_VEHICLE_SPEED,
+ .access = VEHICLE_PROP_ACCESS_READ,
+ .change_mode = VEHICLE_PROP_CHANGE_MODE_CONTINUOUS,
+ .value_type = VEHICLE_VALUE_TYPE_FLOAT,
+ .min_sample_rate = 0.1,
+ .max_sample_rate = 10.0,
+ .hal_data = NULL,
+ },
+ {
+ .prop = VEHICLE_PROPERTY_RADIO_PRESET,
+ .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+ .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+ .value_type = VEHICLE_VALUE_TYPE_INT32_VEC4,
+ .vehicle_radio_num_presets = RADIO_PRESET_NUM,
+ .min_sample_rate = 0,
+ .max_sample_rate = 0,
+ .hal_data = NULL,
+ },
+};
+
+vehicle_prop_config_t* find_config(int prop) {
+ unsigned int i;
+ for (i = 0; i < sizeof(CONFIGS) / sizeof(vehicle_prop_config_t); i++) {
+ if (CONFIGS[i].prop == prop) {
+ return &CONFIGS[i];
+ }
+ }
+ return NULL;
+}
+
+static int alloc_vehicle_str_from_cstr(const char* string, vehicle_str_t* vehicle_str) {
+ int len = strlen(string);
+ vehicle_str->data = (uint8_t*) malloc(len);
+ if (vehicle_str->data == NULL) {
+ return -ENOMEM;
+ }
+ memcpy(vehicle_str->data, string, len);
+ vehicle_str->len = len;
+ return 0;
+}
+
+static vehicle_prop_config_t const * vdev_list_properties(vehicle_hw_device_t* device UNUSED,
+ int* num_properties) {
+ ALOGD("vdev_list_properties.");
+
+ *num_properties = sizeof(CONFIGS) / sizeof(vehicle_prop_config_t);
+ return CONFIGS;
+}
+
+static int vdev_init(vehicle_hw_device_t* device,
+ vehicle_event_callback_fn event_callback_fn,
+ vehicle_error_callback_fn error_callback_fn) {
+ ALOGD("vdev_init.");
+ vehicle_device_impl_t* impl = (vehicle_device_impl_t*)device;
+ pthread_mutex_lock(&lock_);
+ if (impl->initialized_) {
+ ALOGE("vdev_init: Callback and Error functions are already existing.");
+ pthread_mutex_unlock(&lock_);
+ return -EEXIST;
+ }
+
+ impl->initialized_ = 1;
+ impl->event_fn_ = event_callback_fn;
+ impl->error_fn_ = error_callback_fn;
+ pthread_mutex_unlock(&lock_);
+ return 0;
+}
+
+static int vdev_release(vehicle_hw_device_t* device) {
+ vehicle_device_impl_t* impl = (vehicle_device_impl_t*)device;
+ pthread_mutex_lock(&lock_);
+ if (!impl->initialized_) {
+ ALOGD("vdev_release: Already released before, returning early.");
+ } else {
+ // unsubscribe_all()
+ impl->initialized_ = 0;
+ }
+ pthread_mutex_unlock(&lock_);
+ return 0;
+}
+
+static int vdev_get(vehicle_hw_device_t* device UNUSED, vehicle_prop_value_t* data) {
+ ALOGD("vdev_get.");
+ //TODO all data supporting read should support get
+ if (!data) {
+ ALOGE("vdev_get: Data cannot be null.");
+ return -EINVAL;
+ }
+ vehicle_prop_config_t* config = find_config(data->prop);
+ if (config == NULL) {
+ ALOGE("vdev_get: cannot find config 0x%x", data->prop);
+ return -EINVAL;
+ }
+ data->value_type = config->value_type;
+ // for STATIC type, time can be just 0 instead
+ data->timestamp = elapsedRealtimeNano();
+ int r;
+ switch (data->prop) {
+ case VEHICLE_PROPERTY_INFO_MAKE:
+ r = alloc_vehicle_str_from_cstr(VEHICLE_MAKE, &(data->value.str_value));
+ if (r != 0) {
+ ALOGE("vdev_get: alloc failed");
+ return r;
+ }
+ break;
+
+ case VEHICLE_PROPERTY_RADIO_PRESET: {
+ int radio_preset = data->value.int32_array[0];
+ if (radio_preset < VEHICLE_RADIO_PRESET_MIN_VALUE ||
+ radio_preset >= RADIO_PRESET_NUM) {
+ ALOGE("%s Invalid radio preset: %d\n", __func__, radio_preset);
+ return -1;
+ }
+ ALOGD("%s Radio Preset number: %d", __func__, radio_preset);
+ int32_t selector = radio_preset % 2 == 0;
+ // Populate the channel and subchannel to be some variation of the
+ // preset number for mocking.
+
+ // Restore the preset number.
+ data->value.int32_array[0] = radio_preset;
+ // Channel type values taken from
+ // system/core/include/system/radio.h
+ data->value.int32_array[1] = selector ? RADIO_BAND_FM : RADIO_BAND_AM;
+ // For FM set a value in Mhz and for AM set a value in Khz range
+ // (channel).
+ data->value.int32_array[2] = selector ? 99000000 : 100000;
+ // For FM we have a sub-channel and we care about it, for AM pass
+ // a dummy value.
+ data->value.int32_array[3] = selector ? radio_preset : -1;
+ break;
+ }
+
+ default:
+ // actual implementation will be much complex than this. It should track proper last
+ // state. Here just fill with zero.
+ memset(&(data->value), 0, sizeof(data->value));
+ break;
+ }
+ ALOGI("vdev_get, type 0x%x, time %" PRId64 ", value_type %d", data->prop, data->timestamp,
+ data->value_type);
+ return 0;
+}
+
+static int vdev_set(vehicle_hw_device_t* device UNUSED, const vehicle_prop_value_t* data) {
+ ALOGD("vdev_set.");
+ // Just print what data will be setting here.
+ ALOGD("Setting property %d with value type %d\n", data->prop, data->value_type);
+ vehicle_prop_config_t* config = find_config(data->prop);
+ if (config == NULL) {
+ ALOGE("vdev_set: cannot find config 0x%x", data->prop);
+ return -EINVAL;
+ }
+ if (config->value_type != data->value_type) {
+ ALOGE("vdev_set: type mismatch, passed 0x%x expecting 0x%x", data->value_type,
+ config->value_type);
+ return -EINVAL;
+ }
+ switch (data->value_type) {
+ case VEHICLE_VALUE_TYPE_FLOAT:
+ ALOGD("Value type: FLOAT\nValue: %f\n", data->value.float_value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32:
+ ALOGD("Value type: INT32\nValue: %d\n", data->value.int32_value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT64:
+ ALOGD("Value type: INT64\nValue: %lld\n", data->value.int64_value);
+ break;
+ case VEHICLE_VALUE_TYPE_BOOLEAN:
+ ALOGD("Value type: BOOLEAN\nValue: %d\n", data->value.boolean_value);
+ break;
+ case VEHICLE_VALUE_TYPE_STRING:
+ ALOGD("Value type: STRING\n Size: %d\n", data->value.str_value.len);
+ // NOTE: We only handle ASCII strings here.
+ // Print the UTF-8 string.
+ char *ascii_out = (char *) malloc ((data->value.str_value.len + 1) * sizeof (char));
+ memcpy(ascii_out, data->value.str_value.data, data->value.str_value.len);
+ ascii_out[data->value.str_value.len] = '\0';
+ ALOGD("Value: %s\n", ascii_out);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC4:
+ ALOGD("Value type: INT32_VEC4\nValue[0]: %d Value[1] %d Value[2] %d Value[3] %d",
+ data->value.int32_array[0], data->value.int32_array[1],
+ data->value.int32_array[2], data->value.int32_array[3]);
+ break;
+ default:
+ ALOGD("Value type not yet handled: %d.\n", data->value_type);
+ }
+ return 0;
+}
+
+void print_subscribe_info(vehicle_device_impl_t* impl UNUSED) {
+ unsigned int i;
+ for (i = 0; i < sizeof(CONFIGS) / sizeof(vehicle_prop_config_t); i++) {
+ subscription_t* sub = (subscription_t*)CONFIGS[i].hal_data;
+ if (sub != NULL) {
+ ALOGD("prop: %d rate: %f", sub->prop, sub->sample_rate);
+ }
+ }
+}
+
+// This should be run in a separate thread always.
+void fake_event_thread(struct subscription *sub) {
+ if (!sub) {
+ ALOGE("oops! subscription object cannot be NULL.");
+ exit(-1);
+ }
+ prctl(PR_SET_NAME, (unsigned long)sub->name, 0, 0, 0);
+ // Emit values in a loop, every 2 seconds.
+ while (1) {
+ // Create a random value depending on the property type.
+ vehicle_prop_value_t event;
+ event.prop = sub->prop;
+ event.timestamp = elapsedRealtimeNano();
+ switch (sub->prop) {
+ case VEHICLE_PROPERTY_DRIVING_STATUS:
+ event.value_type = VEHICLE_VALUE_TYPE_INT32;
+ switch ((event.timestamp & 0x30000000)>>28) {
+ case 0:
+ event.value.driving_status = VEHICLE_DRIVING_STATUS_UNRESTRICTED;
+ break;
+ case 1:
+ event.value.driving_status = VEHICLE_DRIVING_STATUS_NO_VIDEO;
+ break;
+ case 2:
+ event.value.driving_status = VEHICLE_DRIVING_STATUS_NO_KEYBOARD_INPUT;
+ break;
+ default:
+ event.value.driving_status = VEHICLE_DRIVING_STATUS_NO_CONFIG;
+ }
+ break;
+ case VEHICLE_PROPERTY_GEAR_SELECTION:
+ event.value_type = VEHICLE_VALUE_TYPE_INT32;
+ switch ((event.timestamp & 0x30000000)>>28) {
+ case 0:
+ event.value.gear_selection = VEHICLE_GEAR_PARKING;
+ break;
+ case 1:
+ event.value.gear_selection = VEHICLE_GEAR_NEUTRAL;
+ break;
+ case 2:
+ event.value.gear_selection = VEHICLE_GEAR_DRIVE;
+ break;
+ case 3:
+ event.value.gear_selection = VEHICLE_GEAR_REVERSE;
+ break;
+ }
+ break;
+ case VEHICLE_PROPERTY_PARKING_BRAKE_ON:
+ event.value_type = VEHICLE_VALUE_TYPE_BOOLEAN;
+ if (event.timestamp & 0x20000000) {
+ event.value.parking_brake = VEHICLE_FALSE;
+ } else {
+ event.value.parking_brake = VEHICLE_TRUE;
+ }
+ break;
+ case VEHICLE_PROPERTY_PERF_VEHICLE_SPEED:
+ event.value_type = VEHICLE_VALUE_TYPE_FLOAT;
+ event.value.vehicle_speed = (float) ((event.timestamp & 0xff000000)>>24);
+ break;
+ case VEHICLE_PROPERTY_RADIO_PRESET:
+ event.value_type = VEHICLE_VALUE_TYPE_INT32_VEC4;
+ int presetInfo1[4] = {1 /* preset number */, 0 /* AM Band */, 1000, 0};
+ int presetInfo2[4] = {2 /* preset number */, 1 /* FM Band */, 1000, 0};
+ if (event.timestamp & 0x20000000) {
+ memcpy(event.value.int32_array, presetInfo1, sizeof(presetInfo1));
+ } else {
+ memcpy(event.value.int32_array, presetInfo2, sizeof(presetInfo2));
+ }
+ break;
+ default: // unsupported
+ if (sub->impl == NULL) {
+ ALOGE("subscription impl NULL");
+ return;
+ }
+ if (sub->impl->error_fn_ != NULL) {
+ sub->impl->error_fn_(VEHICLE_ERROR_UNKNOWN, VEHICLE_PROPERTY_INVALID,
+ VEHICLE_OPERATION_GENERIC);
+ } else {
+ ALOGE("Error function is null");
+ }
+ ALOGE("Unsupported prop 0x%x, quit", sub->prop);
+ return;
+ }
+ if (sub->impl->event_fn_ != NULL) {
+ sub->impl->event_fn_(&event);
+ } else {
+ ALOGE("Event function is null");
+ return;
+ }
+ pthread_mutex_lock(&sub->lock);
+ if (sub->stop_thread) {
+ ALOGD("exiting subscription request here.");
+ // Do any cleanup here.
+ pthread_mutex_unlock(&sub->lock);
+ return;
+ }
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+ now.tv_sec += 1; // sleep for one sec
+ pthread_cond_timedwait(&sub->cond, &sub->lock, &now);
+ pthread_mutex_unlock(&sub->lock);
+ }
+}
+
+static int vdev_subscribe(vehicle_hw_device_t* device, int32_t prop, float sample_rate,
+ int32_t zones) {
+ ALOGD("vdev_subscribe 0x%x, %f", prop, sample_rate);
+ vehicle_device_impl_t* impl = (vehicle_device_impl_t*)device;
+ // Check that the device is initialized.
+ pthread_mutex_lock(&lock_);
+ if (!impl->initialized_) {
+ pthread_mutex_unlock(&lock_);
+ ALOGE("vdev_subscribe: have you called init()?");
+ return -EINVAL;
+ }
+ vehicle_prop_config_t* config = find_config(prop);
+ if (config == NULL) {
+ pthread_mutex_unlock(&lock_);
+ ALOGE("vdev_subscribe not supported property 0x%x", prop);
+ return -EINVAL;
+ }
+ if ((config->access != VEHICLE_PROP_ACCESS_READ) &&
+ (config->access != VEHICLE_PROP_ACCESS_READ_WRITE)) {
+ pthread_mutex_unlock(&lock_);
+ ALOGE("vdev_subscribe read not supported on the property 0x%x", prop);
+ return -EINVAL;
+ }
+ if (config->change_mode == VEHICLE_PROP_CHANGE_MODE_STATIC) {
+ pthread_mutex_unlock(&lock_);
+ ALOGE("vdev_subscribe cannot subscribe static property 0x%x", prop);
+ return -EINVAL;
+ }
+ if ((config->change_mode == VEHICLE_PROP_CHANGE_MODE_ON_CHANGE) && (sample_rate != 0)) {
+ pthread_mutex_unlock(&lock_);
+ ALOGE("vdev_subscribe on change type should have 0 sample rate, property 0x%x, sample rate %f",
+ prop, sample_rate);
+ return -EINVAL;
+ }
+ if ((config->max_sample_rate < sample_rate) || (config->min_sample_rate > sample_rate)) {
+
+ ALOGE("vdev_subscribe property 0x%x, invalid sample rate %f, min:%f, max:%f",
+ prop, sample_rate, config->min_sample_rate, config->max_sample_rate);
+ pthread_mutex_unlock(&lock_);
+ return -EINVAL;
+ }
+ subscription_t* sub = (subscription_t*)config->hal_data;
+ if (sub == NULL) {
+ sub = calloc(1, sizeof(subscription_t));
+ sub->prop = prop;
+ sub->sample_rate = sample_rate;
+ sub->stop_thread = 0;
+ sub->impl = impl;
+ pthread_mutex_init(&sub->lock, NULL);
+ pthread_cond_init(&sub->cond, NULL);
+ config->hal_data = sub;
+ sprintf(sub->name, "vhal0x%x", prop);
+ } else if (sub->sample_rate != sample_rate){ // sample rate changed
+ //TODO notify this to fake sensor thread
+ sub->sample_rate = sample_rate;
+ pthread_mutex_unlock(&lock_);
+ return 0;
+ }
+ int ret_code = pthread_create(
+ &sub->thread, NULL, (void *(*)(void*))fake_event_thread, sub);
+ print_subscribe_info(impl);
+ pthread_mutex_unlock(&lock_);
+ return 0;
+}
+
+static int vdev_unsubscribe(vehicle_hw_device_t* device, int32_t prop) {
+ ALOGD("vdev_unsubscribe 0x%x", prop);
+ vehicle_device_impl_t* impl = (vehicle_device_impl_t*)device;
+ pthread_mutex_lock(&lock_);
+ vehicle_prop_config_t* config = find_config(prop);
+ if (config == NULL) {
+ pthread_mutex_unlock(&lock_);
+ return -EINVAL;
+ }
+ subscription_t* sub = (subscription_t*)config->hal_data;
+ if (sub == NULL) {
+ pthread_mutex_unlock(&lock_);
+ return -EINVAL;
+ }
+ config->hal_data = NULL;
+ pthread_mutex_unlock(&lock_);
+ pthread_mutex_lock(&sub->lock);
+ sub->stop_thread = 1;
+ pthread_cond_signal(&sub->cond);
+ pthread_mutex_unlock(&sub->lock);
+ pthread_join(sub->thread, NULL);
+ pthread_cond_destroy(&sub->cond);
+ pthread_mutex_destroy(&sub->lock);
+ free(sub);
+ pthread_mutex_lock(&lock_);
+ print_subscribe_info(impl);
+ pthread_mutex_unlock(&lock_);
+ return 0;
+}
+
+static int vdev_close(hw_device_t* device) {
+ vehicle_device_impl_t* impl = (vehicle_device_impl_t*)device;
+ if (impl) {
+ free(impl);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/*
+ * The open function is provided as an interface in harwdare.h which fills in
+ * all the information about specific implementations and version specific
+ * informations in hw_device_t structure. After calling open() the client should
+ * use the hw_device_t to execute any Vehicle HAL device specific functions.
+ */
+static int vdev_open(const hw_module_t* module, const char* name UNUSED,
+ hw_device_t** device) {
+ ALOGD("vdev_open");
+
+ // Oops, out of memory!
+ vehicle_device_impl_t* vdev = calloc(1, sizeof(vehicle_device_impl_t));
+ if (vdev == NULL) {
+ return -ENOMEM;
+ }
+
+ // Common functions provided by harware.h to access module and device(s).
+ vdev->vehicle_device.common.tag = HARDWARE_DEVICE_TAG;
+ vdev->vehicle_device.common.version = VEHICLE_DEVICE_API_VERSION_1_0;
+ vdev->vehicle_device.common.module = (hw_module_t *) module;
+ vdev->vehicle_device.common.close = vdev_close;
+
+ // Define the Vehicle HAL device specific functions.
+ vdev->vehicle_device.list_properties = vdev_list_properties;
+ vdev->vehicle_device.init = vdev_init;
+ vdev->vehicle_device.release = vdev_release;
+ vdev->vehicle_device.get = vdev_get;
+ vdev->vehicle_device.set = vdev_set;
+ vdev->vehicle_device.subscribe = vdev_subscribe;
+ vdev->vehicle_device.unsubscribe = vdev_unsubscribe;
+
+ *device = (hw_device_t *) vdev;
+ return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+ .open = vdev_open,
+};
+
+/*
+ * This structure is mandatory to be implemented by each HAL implementation. It
+ * exposes the open method (see hw_module_methods_t above) which opens a device.
+ * The vehicle HAL is supposed to be used as a single device HAL hence all the
+ * functions should be implemented inside of the vehicle_hw_device_t struct (see
+ * the vehicle.h in include/ folder.
+ */
+vehicle_module_t HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = VEHICLE_MODULE_API_VERSION_1_0,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = VEHICLE_HARDWARE_MODULE_ID,
+ .name = "Default vehicle HW HAL",
+ .author = "",
+ .methods = &hal_module_methods,
+ },
+};
diff --git a/tests/camera2/CameraModuleFixture.h b/tests/camera2/CameraModuleFixture.h
index 3a2df69..661c693 100644
--- a/tests/camera2/CameraModuleFixture.h
+++ b/tests/camera2/CameraModuleFixture.h
@@ -23,7 +23,6 @@
#include "hardware/camera2.h"
#include <common/CameraModule.h>
-#include <device2/Camera2Device.h>
#include <device3/Camera3Device.h>
#include "camera2_utils.h"
@@ -92,14 +91,10 @@
struct camera_info info;
ASSERT_EQ(OK, mModule->getCameraInfo(cameraID, &info));
- ASSERT_GE((int)info.device_version, CAMERA_DEVICE_API_VERSION_2_0) <<
+ ASSERT_GE((int)info.device_version, CAMERA_DEVICE_API_VERSION_3_0) <<
"Device version too old for camera " << cameraID << ". Version: " <<
info.device_version;
switch(info.device_version) {
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
- *device = new Camera2Device(cameraID);
- break;
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
diff --git a/tests/camera2/CameraStreamTests.cpp b/tests/camera2/CameraStreamTests.cpp
index a3b8c47..de9ae8a 100644
--- a/tests/camera2/CameraStreamTests.cpp
+++ b/tests/camera2/CameraStreamTests.cpp
@@ -29,8 +29,6 @@
#include <gui/CpuConsumer.h>
#include <gui/Surface.h>
-#include <device2/Camera2Device.h>
-
#include "CameraStreamFixture.h"
#include "TestExtensions.h"
diff --git a/tests/input/evdev/Android.mk b/tests/input/evdev/Android.mk
index 8761da8..3aeb2f8 100644
--- a/tests/input/evdev/Android.mk
+++ b/tests/input/evdev/Android.mk
@@ -2,12 +2,19 @@
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += hardware/libhardware/modules/input/evdev
+LOCAL_C_INCLUDES += $(TOP)/external/gmock/include
LOCAL_SRC_FILES:= \
+ BitUtils_test.cpp \
InputDevice_test.cpp \
InputHub_test.cpp \
+ InputMocks.cpp \
+ MouseInputMapper_test.cpp \
+ SwitchInputMapper_test.cpp \
TestHelpers.cpp
+LOCAL_STATIC_LIBRARIES := libgmock
+
LOCAL_SHARED_LIBRARIES := \
libinput_evdev \
liblog \
diff --git a/tests/input/evdev/BitUtils_test.cpp b/tests/input/evdev/BitUtils_test.cpp
new file mode 100644
index 0000000..76fc8af
--- /dev/null
+++ b/tests/input/evdev/BitUtils_test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 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 "BitUtils.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace tests {
+
+TEST(BitInRange, testInvalidRange) {
+ uint8_t arr[2] = { 0xff, 0xff };
+ EXPECT_FALSE(testBitInRange(arr, 0, 0));
+ EXPECT_FALSE(testBitInRange(arr, 1, 0));
+}
+
+TEST(BitInRange, testNoBits) {
+ uint8_t arr[1];
+ arr[0] = 0;
+ EXPECT_FALSE(testBitInRange(arr, 0, 8));
+}
+
+TEST(BitInRange, testOneBit) {
+ uint8_t arr[1];
+ for (int i = 0; i < 8; ++i) {
+ arr[0] = 1 << i;
+ EXPECT_TRUE(testBitInRange(arr, 0, 8));
+ }
+}
+
+TEST(BitInRange, testZeroStart) {
+ uint8_t arr[1] = { 0x10 };
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_FALSE(testBitInRange(arr, 0, i));
+ }
+ for (int i = 5; i <= 8; ++i) {
+ EXPECT_TRUE(testBitInRange(arr, 0, i));
+ }
+}
+
+TEST(BitInRange, testByteBoundaryEnd) {
+ uint8_t arr[1] = { 0x10 };
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_TRUE(testBitInRange(arr, i, 8));
+ }
+ for (int i = 5; i <= 8; ++i) {
+ EXPECT_FALSE(testBitInRange(arr, i, 8));
+ }
+}
+
+TEST(BitInRange, testMultiByteArray) {
+ // bits set: 11 and 16
+ uint8_t arr[3] = { 0x00, 0x08, 0x01 };
+ for (int start = 0; start < 24; ++start) {
+ for (int end = start + 1; end <= 24; ++end) {
+ if (start > 16 || end <= 11 || (start > 11 && end <= 16)) {
+ EXPECT_FALSE(testBitInRange(arr, start, end))
+ << "range = (" << start << ", " << end << ")";
+ } else {
+ EXPECT_TRUE(testBitInRange(arr, start, end))
+ << "range = (" << start << ", " << end << ")";
+ }
+ }
+ }
+}
+
+} // namespace tests
+} // namespace android
diff --git a/tests/input/evdev/InputDevice_test.cpp b/tests/input/evdev/InputDevice_test.cpp
index a96d664..bd57491 100644
--- a/tests/input/evdev/InputDevice_test.cpp
+++ b/tests/input/evdev/InputDevice_test.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "InputHub_test"
-//#define LOG_NDEBUG 0
+#include "InputDevice.h"
+
+#include <memory>
#include <linux/input.h>
@@ -23,8 +24,9 @@
#include <utils/Timers.h>
-#include "InputDevice.h"
#include "InputHub.h"
+#include "InputMocks.h"
+#include "MockInputHost.h"
// # of milliseconds to allow for timing measurements
#define TIMING_TOLERANCE_MS 25
@@ -32,45 +34,41 @@
#define MSC_ANDROID_TIME_SEC 0x6
#define MSC_ANDROID_TIME_USEC 0x7
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::ReturnNull;
+
namespace android {
namespace tests {
-class MockInputDeviceNode : public InputDeviceNode {
- virtual const std::string& getPath() const override { return mPath; }
+class EvdevDeviceTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ // Creating device identifiers and definitions should always happen.
+ EXPECT_CALL(mHost, createDeviceIdentifier(_, _, _, _, _))
+ .WillOnce(ReturnNull());
+ EXPECT_CALL(mHost, createDeviceDefinition())
+ .WillOnce(Return(&mDeviceDef));
+ // InputMappers may cause any of these to be called, but we are not
+ // testing these here.
+ ON_CALL(mHost, createInputReportDefinition())
+ .WillByDefault(Return(&mReportDef));
+ ON_CALL(mHost, createOutputReportDefinition())
+ .WillByDefault(Return(&mReportDef));
+ ON_CALL(mHost, registerDevice(_, _))
+ .WillByDefault(ReturnNull());
+ }
- virtual const std::string& getName() const override { return mName; }
- virtual const std::string& getLocation() const override { return mLocation; }
- virtual const std::string& getUniqueId() const override { return mUniqueId; }
-
- virtual uint16_t getBusType() const override { return 0; }
- virtual uint16_t getVendorId() const override { return 0; }
- virtual uint16_t getProductId() const override { return 0; }
- virtual uint16_t getVersion() const override { return 0; }
-
- virtual bool hasKey(int32_t key) const { return false; }
- virtual bool hasRelativeAxis(int axis) const { return false; }
- virtual bool hasInputProperty(int property) const { return false; }
-
- virtual int32_t getKeyState(int32_t key) const { return 0; }
- virtual int32_t getSwitchState(int32_t sw) const { return 0; }
- virtual const AbsoluteAxisInfo* getAbsoluteAxisInfo(int32_t axis) const { return nullptr; }
- virtual status_t getAbsoluteAxisValue(int32_t axis, int32_t* outValue) const { return 0; }
-
- virtual void vibrate(nsecs_t duration) {}
- virtual void cancelVibrate(int32_t deviceId) {}
-
- virtual void disableDriverKeyRepeat() {}
-
-private:
- std::string mPath = "/test";
- std::string mName = "Test Device";
- std::string mLocation = "test/0";
- std::string mUniqueId = "test-id";
+ MockInputHost mHost;
+ // Ignore uninteresting calls on the report definitions by using NiceMocks.
+ NiceMock<MockInputReportDefinition> mReportDef;
+ NiceMock<MockInputDeviceDefinition> mDeviceDef;
};
-TEST(EvdevDeviceTest, testOverrideTime) {
+TEST_F(EvdevDeviceTest, testOverrideTime) {
auto node = std::make_shared<MockInputDeviceNode>();
- auto device = std::make_unique<EvdevDevice>(node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
ASSERT_TRUE(device != nullptr);
// Send two timestamp override events before an input event.
@@ -97,9 +95,9 @@
EXPECT_EQ(when, keyUp.when);
}
-TEST(EvdevDeviceTest, testWrongClockCorrection) {
+TEST_F(EvdevDeviceTest, testWrongClockCorrection) {
auto node = std::make_shared<MockInputDeviceNode>();
- auto device = std::make_unique<EvdevDevice>(node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
ASSERT_TRUE(device != nullptr);
auto now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -113,9 +111,9 @@
EXPECT_NEAR(now, event.when, ms2ns(TIMING_TOLERANCE_MS));
}
-TEST(EvdevDeviceTest, testClockCorrectionOk) {
+TEST_F(EvdevDeviceTest, testClockCorrectionOk) {
auto node = std::make_shared<MockInputDeviceNode>();
- auto device = std::make_unique<EvdevDevice>(node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
ASSERT_TRUE(device != nullptr);
auto now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -130,5 +128,73 @@
EXPECT_NEAR(now, event.when, ms2ns(TIMING_TOLERANCE_MS));
}
+TEST_F(EvdevDeviceTest, testN7v2Touchscreen) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getElanTouchscreen());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_TOUCH|INPUT_DEVICE_CLASS_TOUCH_MT,
+ device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testN7v2ButtonJack) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getButtonJack());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testN7v2HeadsetJack) {
+ // Eventually these mock device tests will all expect these calls. For now
+ // only the SwitchInputMapper has been implemented.
+ // TODO: move this expectation out to a common function
+ EXPECT_CALL(mHost, createInputReportDefinition());
+ EXPECT_CALL(mHost, createOutputReportDefinition());
+ EXPECT_CALL(mHost, freeReportDefinition(_));
+ EXPECT_CALL(mHost, registerDevice(_, _));
+
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getHeadsetJack());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_SWITCH, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testN7v2H2wButton) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getH2wButton());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testN7v2GpioKeys) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getGpioKeys());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testNexusPlayerGpioKeys) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getGpioKeys());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testNexusPlayerMidPowerBtn) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getMidPowerBtn());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testNexusRemote) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getNexusRemote());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testAsusGamepad) {
+ auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getAsusGamepad());
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+ EXPECT_EQ(INPUT_DEVICE_CLASS_JOYSTICK|INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
+}
+
+TEST_F(EvdevDeviceTest, testMocks) {
+ auto node = std::make_shared<MockInputDeviceNode>();
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
+}
+
} // namespace tests
} // namespace android
diff --git a/tests/input/evdev/InputHub_test.cpp b/tests/input/evdev/InputHub_test.cpp
index f2c8edf..64671ff 100644
--- a/tests/input/evdev/InputHub_test.cpp
+++ b/tests/input/evdev/InputHub_test.cpp
@@ -14,22 +14,19 @@
* limitations under the License.
*/
-#define LOG_TAG "InputHub_test"
-//#define LOG_NDEBUG 0
-
-#include <linux/input.h>
+#include "InputHub.h"
#include <chrono>
#include <memory>
#include <mutex>
+#include <linux/input.h>
+
#include <gtest/gtest.h>
-#include <utils/Log.h>
#include <utils/StopWatch.h>
#include <utils/Timers.h>
-#include "InputHub.h"
#include "TestHelpers.h"
// # of milliseconds to fudge stopwatch measurements
@@ -41,11 +38,11 @@
using namespace std::literals::chrono_literals;
-using InputCbFunc = std::function<void(std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t)>;
-using DeviceCbFunc = std::function<void(std::shared_ptr<InputDeviceNode>)>;
+using InputCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t)>;
+using DeviceCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&)>;
-static const InputCbFunc kNoopInputCb = [](std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t){};
-static const DeviceCbFunc kNoopDeviceCb = [](std::shared_ptr<InputDeviceNode>){};
+static const InputCbFunc kNoopInputCb = [](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t){};
+static const DeviceCbFunc kNoopDeviceCb = [](const std::shared_ptr<InputDeviceNode>&){};
class TestInputCallback : public InputCallbackInterface {
public:
@@ -57,14 +54,14 @@
void setDeviceAddedCallback(DeviceCbFunc cb) { mDeviceAddedCb = cb; }
void setDeviceRemovedCallback(DeviceCbFunc cb) { mDeviceRemovedCb = cb; }
- virtual void onInputEvent(std::shared_ptr<InputDeviceNode> node, InputEvent& event,
+ virtual void onInputEvent(const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
nsecs_t event_time) override {
mInputCb(node, event, event_time);
}
- virtual void onDeviceAdded(std::shared_ptr<InputDeviceNode> node) override {
+ virtual void onDeviceAdded(const std::shared_ptr<InputDeviceNode>& node) override {
mDeviceAddedCb(node);
}
- virtual void onDeviceRemoved(std::shared_ptr<InputDeviceNode> node) override {
+ virtual void onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) override {
mDeviceRemovedCb(node);
}
@@ -101,7 +98,7 @@
std::string pathname;
// Expect that this callback will run and set handle and pathname.
mCallback->setDeviceAddedCallback(
- [&](std::shared_ptr<InputDeviceNode> node) {
+ [&](const std::shared_ptr<InputDeviceNode>& node) {
pathname = node->getPath();
});
@@ -136,11 +133,11 @@
std::shared_ptr<InputDeviceNode> tempNode;
// Expect that these callbacks will run for the above device file.
mCallback->setDeviceAddedCallback(
- [&](std::shared_ptr<InputDeviceNode> node) {
+ [&](const std::shared_ptr<InputDeviceNode>& node) {
tempNode = node;
});
mCallback->setDeviceRemovedCallback(
- [&](std::shared_ptr<InputDeviceNode> node) {
+ [&](const std::shared_ptr<InputDeviceNode>& node) {
EXPECT_EQ(tempNode, node);
});
@@ -182,7 +179,8 @@
// Expect this callback to run when the input event is read.
nsecs_t expectedWhen = systemTime(CLOCK_MONOTONIC) + ms2ns(inputDelayMs.count());
mCallback->setInputCallback(
- [&](std::shared_ptr<InputDeviceNode> node, InputEvent& event, nsecs_t event_time) {
+ [&](const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
+ nsecs_t event_time) {
EXPECT_NEAR(expectedWhen, event_time, ms2ns(TIMING_TOLERANCE_MS));
EXPECT_EQ(s2ns(1), event.when);
EXPECT_EQ(tempFileName, node->getPath());
@@ -211,7 +209,7 @@
// Setup the callback for input events. Should run before the device
// callback.
mCallback->setInputCallback(
- [&](std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t) {
+ [&](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t) {
ASSERT_FALSE(deviceCallbackFinished);
inputCallbackFinished = true;
});
@@ -219,7 +217,7 @@
// Setup the callback for device removal. Should run after the input
// callback.
mCallback->setDeviceRemovedCallback(
- [&](std::shared_ptr<InputDeviceNode> node) {
+ [&](const std::shared_ptr<InputDeviceNode>& node) {
ASSERT_TRUE(inputCallbackFinished)
<< "input callback did not run before device changed callback";
// Make sure the correct device was removed.
diff --git a/tests/input/evdev/InputMocks.cpp b/tests/input/evdev/InputMocks.cpp
new file mode 100644
index 0000000..bd09a3d
--- /dev/null
+++ b/tests/input/evdev/InputMocks.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2015 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 "InputMocks.h"
+
+namespace android {
+
+bool MockInputDeviceNode::hasKeyInRange(int32_t startKey, int32_t endKey) const {
+ auto iter = mKeys.lower_bound(startKey);
+ if (iter == mKeys.end()) return false;
+ return *iter < endKey;
+}
+
+namespace MockNexus7v2 {
+
+MockInputDeviceNode* getElanTouchscreen() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event0");
+ node->setName("elan-touchscreen");
+ // Location not set
+ // UniqueId not set
+ node->setBusType(0);
+ node->setVendorId(0);
+ node->setProductId(0);
+ node->setVersion(0);
+ // No keys
+ // No relative axes
+ // TODO: set the AbsoluteAxisInfo pointers
+ node->addAbsAxis(ABS_MT_SLOT, nullptr);
+ node->addAbsAxis(ABS_MT_TOUCH_MAJOR, nullptr);
+ node->addAbsAxis(ABS_MT_POSITION_X, nullptr);
+ node->addAbsAxis(ABS_MT_POSITION_Y, nullptr);
+ node->addAbsAxis(ABS_MT_TRACKING_ID, nullptr);
+ node->addAbsAxis(ABS_MT_PRESSURE, nullptr);
+ // No switches
+ // No forcefeedback
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getLidInput() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event1");
+ node->setName("lid_input");
+ node->setLocation("/dev/input/lid_indev");
+ // UniqueId not set
+ node->setBusType(0);
+ node->setVendorId(0);
+ node->setProductId(0);
+ node->setVersion(0);
+ // No keys
+ // No relative axes
+ // No absolute axes
+ node->addSwitch(SW_LID);
+ // No forcefeedback
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getButtonJack() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event2");
+ node->setName("apq8064-tabla-snd-card Button Jack");
+ node->setLocation("ALSA");
+ // UniqueId not set
+ node->setBusType(0);
+ node->setVendorId(0);
+ node->setProductId(0);
+ node->setVersion(0);
+ node->addKeys(BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7);
+ // No relative axes
+ // No absolute axes
+ // No switches
+ // No forcefeedback
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getHeadsetJack() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event3");
+ node->setName("apq8064-tabla-snd-card Headset Jack");
+ node->setLocation("ALSA");
+ // UniqueId not set
+ node->setBusType(0);
+ node->setVendorId(0);
+ node->setProductId(0);
+ node->setVersion(0);
+ // No keys
+ // No relative axes
+ // No absolute axes
+ node->addSwitch(SW_HEADPHONE_INSERT);
+ node->addSwitch(SW_MICROPHONE_INSERT);
+ node->addSwitch(SW_LINEOUT_INSERT);
+ // ASUS adds some proprietary switches, but we'll only see two of them.
+ node->addSwitch(0x0e); // SW_HPHL_OVERCURRENT
+ node->addSwitch(0x0f); // SW_HPHR_OVERCURRENT
+ // No forcefeedback
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getH2wButton() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event4");
+ node->setName("h2w button");
+ // Location not set
+ // UniqueId not set
+ node->setBusType(0);
+ node->setVendorId(0);
+ node->setProductId(0);
+ node->setVersion(0);
+ node->addKeys(KEY_MEDIA);
+ // No relative axes
+ // No absolute axes
+ // No switches
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getGpioKeys() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event5");
+ node->setName("gpio-keys");
+ node->setLocation("gpio-keys/input0");
+ // UniqueId not set
+ node->setBusType(0x0019);
+ node->setVendorId(0x0001);
+ node->setProductId(0x0001);
+ node->setVersion(0x0100);
+ node->addKeys(KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_POWER);
+ // No relative axes
+ // No absolute axes
+ // No switches
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+} // namespace MockNexus7v2
+
+namespace MockNexusPlayer {
+
+MockInputDeviceNode* getGpioKeys() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event0");
+ node->setName("gpio-keys");
+ node->setLocation("gpio-keys/input0");
+ // UniqueId not set
+ node->setBusType(0x0019);
+ node->setVendorId(0x0001);
+ node->setProductId(0x0001);
+ node->setVersion(0x0100);
+ node->addKeys(KEY_CONNECT);
+ // No relative axes
+ // No absolute axes
+ // No switches
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getMidPowerBtn() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event1");
+ node->setName("mid_powerbtn");
+ node->setLocation("power-button/input0");
+ // UniqueId not set
+ node->setBusType(0x0019);
+ node->setVendorId(0);
+ node->setProductId(0);
+ node->setVersion(0);
+ node->addKeys(KEY_POWER);
+ // No relative axes
+ // No absolute axes
+ // No switches
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getNexusRemote() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event2");
+ node->setName("Nexus Remote");
+ // Location not set
+ node->setUniqueId("78:86:D9:50:A0:54");
+ node->setBusType(0x0005);
+ node->setVendorId(0x18d1);
+ node->setProductId(0x2c42);
+ node->setVersion(0);
+ node->addKeys(KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_BACK, KEY_PLAYPAUSE,
+ KEY_HOMEPAGE, KEY_SEARCH, KEY_SELECT);
+ // No relative axes
+ node->addAbsAxis(ABS_MISC, nullptr);
+ // No switches
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ return node;
+}
+
+MockInputDeviceNode* getAsusGamepad() {
+ auto node = new MockInputDeviceNode();
+ node->setPath("/dev/input/event3");
+ node->setName("ASUS Gamepad");
+ // Location not set
+ node->setUniqueId("C5:30:CD:50:A0:54");
+ node->setBusType(0x0005);
+ node->setVendorId(0x0b05);
+ node->setProductId(0x4500);
+ node->setVersion(0x0040);
+ node->addKeys(KEY_BACK, KEY_HOMEPAGE, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_TL, BTN_TR,
+ BTN_MODE, BTN_THUMBL, BTN_THUMBR);
+ // No relative axes
+ node->addAbsAxis(ABS_X, nullptr);
+ node->addAbsAxis(ABS_Y, nullptr);
+ node->addAbsAxis(ABS_Z, nullptr);
+ node->addAbsAxis(ABS_RZ, nullptr);
+ node->addAbsAxis(ABS_GAS, nullptr);
+ node->addAbsAxis(ABS_BRAKE, nullptr);
+ node->addAbsAxis(ABS_HAT0X, nullptr);
+ node->addAbsAxis(ABS_HAT0Y, nullptr);
+ node->addAbsAxis(ABS_MISC, nullptr);
+ node->addAbsAxis(0x29, nullptr);
+ node->addAbsAxis(0x2a, nullptr);
+ // No switches
+ node->addInputProperty(INPUT_PROP_DIRECT);
+ // Note: this device has MSC and LED bitmaps as well.
+ return node;
+}
+
+} // namespace MockNexusPlayer
+
+} // namespace android
diff --git a/tests/input/evdev/InputMocks.h b/tests/input/evdev/InputMocks.h
new file mode 100644
index 0000000..78e0279
--- /dev/null
+++ b/tests/input/evdev/InputMocks.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 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_INPUT_MOCKS_H_
+#define ANDROID_INPUT_MOCKS_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include <linux/input.h>
+
+#include "InputHub.h"
+
+namespace android {
+
+class MockInputDeviceNode : public InputDeviceNode {
+public:
+ MockInputDeviceNode() = default;
+ virtual ~MockInputDeviceNode() = default;
+
+ virtual const std::string& getPath() const override { return mPath; }
+ virtual const std::string& getName() const override { return mName; }
+ virtual const std::string& getLocation() const override { return mLocation; }
+ virtual const std::string& getUniqueId() const override { return mUniqueId; }
+
+ void setPath(const std::string& path) { mPath = path; }
+ void setName(const std::string& name) { mName = name; }
+ void setLocation(const std::string& location) { mLocation = location; }
+ void setUniqueId(const std::string& uniqueId) { mUniqueId = uniqueId; }
+
+ virtual uint16_t getBusType() const override { return mBusType; }
+ virtual uint16_t getVendorId() const override { return mVendorId; }
+ virtual uint16_t getProductId() const override { return mProductId; }
+ virtual uint16_t getVersion() const override { return mVersion; }
+
+ void setBusType(uint16_t busType) { mBusType = busType; }
+ void setVendorId(uint16_t vendorId) { mVendorId = vendorId; }
+ void setProductId(uint16_t productId) { mProductId = productId; }
+ void setVersion(uint16_t version) { mVersion = version; }
+
+ virtual bool hasKey(int32_t key) const override { return mKeys.count(key); }
+ virtual bool hasKeyInRange(int32_t startKey, int32_t endKey) const override;
+ virtual bool hasRelativeAxis(int axis) const override { return mRelAxes.count(axis); }
+ virtual bool hasAbsoluteAxis(int32_t axis) const override { return mAbsAxes.count(axis); }
+ virtual bool hasSwitch(int32_t sw) const override { return mSwitches.count(sw); }
+ virtual bool hasForceFeedback(int32_t ff) const override { return mForceFeedbacks.count(ff); }
+ virtual bool hasInputProperty(int32_t property) const override {
+ return mInputProperties.count(property);
+ }
+
+ // base case
+ void addKeys() {}
+ // inductive case
+ template<typename I, typename... Is>
+ void addKeys(I key, Is... keys) {
+ // Add the first key
+ mKeys.insert(key);
+ // Recursively add the remaining keys
+ addKeys(keys...);
+ }
+
+ void addRelAxis(int32_t axis) { mRelAxes.insert(axis); }
+ void addAbsAxis(int32_t axis, AbsoluteAxisInfo* info) { mAbsAxes[axis] = info; }
+ void addSwitch(int32_t sw) { mSwitches.insert(sw); }
+ void addForceFeedback(int32_t ff) { mForceFeedbacks.insert(ff); }
+ void addInputProperty(int32_t property) { mInputProperties.insert(property); }
+
+ virtual int32_t getKeyState(int32_t key) const override { return 0; }
+ virtual int32_t getSwitchState(int32_t sw) const override { return 0; }
+ virtual const AbsoluteAxisInfo* getAbsoluteAxisInfo(int32_t axis) const override {
+ auto iter = mAbsAxes.find(axis);
+ if (iter != mAbsAxes.end()) {
+ return iter->second;
+ }
+ return nullptr;
+ }
+ virtual status_t getAbsoluteAxisValue(int32_t axis, int32_t* outValue) const override {
+ // TODO
+ return 0;
+ }
+
+ virtual void vibrate(nsecs_t duration) override {}
+ virtual void cancelVibrate() override {}
+
+ virtual void disableDriverKeyRepeat() override { mKeyRepeatDisabled = true; }
+
+ bool isDriverKeyRepeatEnabled() { return mKeyRepeatDisabled; }
+
+private:
+ std::string mPath = "/test";
+ std::string mName = "Test Device";
+ std::string mLocation = "test/0";
+ std::string mUniqueId = "test-id";
+
+ uint16_t mBusType = 0;
+ uint16_t mVendorId = 0;
+ uint16_t mProductId = 0;
+ uint16_t mVersion = 0;
+
+ std::set<int32_t> mKeys;
+ std::set<int32_t> mRelAxes;
+ std::map<int32_t, AbsoluteAxisInfo*> mAbsAxes;
+ std::set<int32_t> mSwitches;
+ std::set<int32_t> mForceFeedbacks;
+ std::set<int32_t> mInputProperties;
+
+ bool mKeyRepeatDisabled = false;
+};
+
+namespace MockNexus7v2 {
+MockInputDeviceNode* getElanTouchscreen();
+MockInputDeviceNode* getLidInput();
+MockInputDeviceNode* getButtonJack();
+MockInputDeviceNode* getHeadsetJack();
+MockInputDeviceNode* getH2wButton();
+MockInputDeviceNode* getGpioKeys();
+} // namespace MockNexus7v2
+
+namespace MockNexusPlayer {
+MockInputDeviceNode* getGpioKeys();
+MockInputDeviceNode* getMidPowerBtn();
+MockInputDeviceNode* getNexusRemote();
+MockInputDeviceNode* getAsusGamepad();
+} // namespace MockNexusPlayer
+
+} // namespace android
+
+#endif // ANDROID_INPUT_MOCKS_H_
diff --git a/tests/input/evdev/MockInputHost.h b/tests/input/evdev/MockInputHost.h
new file mode 100644
index 0000000..aae0564
--- /dev/null
+++ b/tests/input/evdev/MockInputHost.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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_MOCK_INPUT_HOST_H_
+#define ANDROID_MOCK_INPUT_HOST_H_
+
+#include "InputHost.h"
+
+#include "gmock/gmock.h"
+
+
+namespace android {
+namespace tests {
+
+class MockInputReport : public InputReport {
+public:
+ MockInputReport() : InputReport(nullptr, {}, nullptr) {}
+ MOCK_METHOD4(setIntUsage, void(InputCollectionId id, InputUsage usage, int32_t value,
+ int32_t arityIndex));
+ MOCK_METHOD4(setBoolUsage, void(InputCollectionId id, InputUsage usage, bool value,
+ int32_t arityIndex));
+ MOCK_METHOD1(reportEvent, void(InputDeviceHandle* d));
+};
+
+class MockInputReportDefinition : public InputReportDefinition {
+public:
+ MockInputReportDefinition() : InputReportDefinition(nullptr, {}, nullptr) {}
+ MOCK_METHOD2(addCollection, void(InputCollectionId id, int32_t arity));
+ MOCK_METHOD5(declareUsage, void(InputCollectionId id, InputUsage usage, int32_t min,
+ int32_t max, float resolution));
+ MOCK_METHOD3(declareUsages, void(InputCollectionId id, InputUsage* usage, size_t usageCount));
+ MOCK_METHOD0(allocateReport, InputReport*());
+};
+
+class MockInputDeviceDefinition : public InputDeviceDefinition {
+public:
+ MockInputDeviceDefinition() : InputDeviceDefinition(nullptr, {}, nullptr) {}
+ MOCK_METHOD1(addReport, void(InputReportDefinition* r));
+};
+
+class MockInputProperty : public InputProperty {
+public:
+ MockInputProperty() : InputProperty(nullptr, {}, nullptr) {}
+ virtual ~MockInputProperty() {}
+ MOCK_CONST_METHOD0(getKey, const char*());
+ MOCK_CONST_METHOD0(getValue, const char*());
+};
+
+class MockInputPropertyMap : public InputPropertyMap {
+public:
+ MockInputPropertyMap() : InputPropertyMap(nullptr, {}, nullptr) {}
+ virtual ~MockInputPropertyMap() {}
+ MOCK_CONST_METHOD1(getDeviceProperty, InputProperty*(const char* key));
+ MOCK_CONST_METHOD1(freeDeviceProperty, void(InputProperty* property));
+};
+
+class MockInputHost : public InputHostInterface {
+public:
+ MOCK_METHOD5(createDeviceIdentifier, InputDeviceIdentifier*(
+ const char* name, int32_t productId, int32_t vendorId, InputBus bus,
+ const char* uniqueId));
+ MOCK_METHOD0(createDeviceDefinition, InputDeviceDefinition*());
+ MOCK_METHOD0(createInputReportDefinition, InputReportDefinition*());
+ MOCK_METHOD0(createOutputReportDefinition, InputReportDefinition*());
+ MOCK_METHOD1(freeReportDefinition, void(InputReportDefinition* reportDef));
+ MOCK_METHOD2(registerDevice, InputDeviceHandle*(InputDeviceIdentifier* id,
+ InputDeviceDefinition* d));
+ MOCK_METHOD1(unregisterDevice, void(InputDeviceHandle* handle));
+ MOCK_METHOD1(getDevicePropertyMap, InputPropertyMap*(InputDeviceIdentifier* id));
+ MOCK_METHOD1(freeDevicePropertyMap, void(InputPropertyMap* propertyMap));
+};
+
+} // namespace tests
+} // namespace android
+
+#endif // ANDROID_MOCK_INPUT_HOST_H_
diff --git a/tests/input/evdev/MouseInputMapper_test.cpp b/tests/input/evdev/MouseInputMapper_test.cpp
new file mode 100644
index 0000000..7e1f376
--- /dev/null
+++ b/tests/input/evdev/MouseInputMapper_test.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 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 <memory>
+
+#include <linux/input.h>
+
+#include <gtest/gtest.h>
+
+#include "InputMocks.h"
+#include "MockInputHost.h"
+#include "MouseInputMapper.h"
+
+using ::testing::_;
+using ::testing::Args;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::UnorderedElementsAre;
+
+namespace android {
+namespace tests {
+
+class MouseInputMapperTest : public ::testing::Test {
+protected:
+ virtual void SetUp() override {
+ mMapper = std::make_unique<MouseInputMapper>();
+ }
+
+ MockInputHost mHost;
+ std::unique_ptr<MouseInputMapper> mMapper;
+};
+
+TEST_F(MouseInputMapperTest, testConfigureDevice) {
+ MockInputReportDefinition reportDef;
+ MockInputDeviceNode deviceNode;
+ deviceNode.addKeys(BTN_LEFT, BTN_RIGHT, BTN_MIDDLE);
+ deviceNode.addRelAxis(REL_X);
+ deviceNode.addRelAxis(REL_Y);
+
+ const auto id = INPUT_COLLECTION_ID_MOUSE;
+ EXPECT_CALL(reportDef, addCollection(id, 1));
+ EXPECT_CALL(reportDef, declareUsage(id, INPUT_USAGE_AXIS_X, _, _, _));
+ EXPECT_CALL(reportDef, declareUsage(id, INPUT_USAGE_AXIS_Y, _, _, _));
+ EXPECT_CALL(reportDef, declareUsages(id, _, 3))
+ .With(Args<1,2>(UnorderedElementsAre(
+ INPUT_USAGE_BUTTON_PRIMARY,
+ INPUT_USAGE_BUTTON_SECONDARY,
+ INPUT_USAGE_BUTTON_TERTIARY)));
+
+ EXPECT_TRUE(mMapper->configureInputReport(&deviceNode, &reportDef));
+}
+
+TEST_F(MouseInputMapperTest, testConfigureDevice_noXAxis) {
+ MockInputReportDefinition reportDef;
+ MockInputDeviceNode deviceNode;
+
+ EXPECT_CALL(reportDef, addCollection(INPUT_COLLECTION_ID_MOUSE, 1));
+ EXPECT_CALL(reportDef, declareUsage(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(reportDef, declareUsages(_, _, _)).Times(0);
+
+ EXPECT_FALSE(mMapper->configureInputReport(&deviceNode, &reportDef));
+}
+
+TEST_F(MouseInputMapperTest, testProcessInput) {
+ MockInputReportDefinition reportDef;
+ MockInputDeviceNode deviceNode;
+ deviceNode.addKeys(BTN_LEFT, BTN_RIGHT, BTN_MIDDLE);
+ deviceNode.addRelAxis(REL_X);
+ deviceNode.addRelAxis(REL_Y);
+
+ EXPECT_CALL(reportDef, addCollection(_, _));
+ EXPECT_CALL(reportDef, declareUsage(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(reportDef, declareUsages(_, _, 3));
+
+ mMapper->configureInputReport(&deviceNode, &reportDef);
+
+ MockInputReport report;
+ EXPECT_CALL(reportDef, allocateReport())
+ .WillOnce(Return(&report));
+
+ {
+ // Test two switch events in order
+ InSequence s;
+ const auto id = INPUT_COLLECTION_ID_MOUSE;
+ EXPECT_CALL(report, setIntUsage(id, INPUT_USAGE_AXIS_X, 5, 0));
+ EXPECT_CALL(report, setIntUsage(id, INPUT_USAGE_AXIS_Y, -3, 0));
+ EXPECT_CALL(report, reportEvent(_));
+ EXPECT_CALL(report, setBoolUsage(id, INPUT_USAGE_BUTTON_PRIMARY, 1, 0));
+ EXPECT_CALL(report, reportEvent(_));
+ EXPECT_CALL(report, setBoolUsage(id, INPUT_USAGE_BUTTON_PRIMARY, 0, 0));
+ EXPECT_CALL(report, reportEvent(_));
+ }
+
+ InputEvent events[] = {
+ {0, EV_REL, REL_X, 5},
+ {1, EV_REL, REL_Y, -3},
+ {2, EV_SYN, SYN_REPORT, 0},
+ {0, EV_KEY, BTN_LEFT, 1},
+ {1, EV_SYN, SYN_REPORT, 0},
+ {2, EV_KEY, BTN_LEFT, 0},
+ {3, EV_SYN, SYN_REPORT, 0},
+ };
+ for (auto e : events) {
+ mMapper->process(e);
+ }
+}
+
+} // namespace tests
+} // namespace android
+
diff --git a/tests/input/evdev/SwitchInputMapper_test.cpp b/tests/input/evdev/SwitchInputMapper_test.cpp
new file mode 100644
index 0000000..ee90b2c
--- /dev/null
+++ b/tests/input/evdev/SwitchInputMapper_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 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 <memory>
+
+#include <linux/input.h>
+
+#include <gtest/gtest.h>
+
+#include "InputMocks.h"
+#include "MockInputHost.h"
+#include "SwitchInputMapper.h"
+
+using ::testing::_;
+using ::testing::Args;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::UnorderedElementsAre;
+
+namespace android {
+namespace tests {
+
+class SwitchInputMapperTest : public ::testing::Test {
+protected:
+ virtual void SetUp() override {
+ mMapper = std::make_unique<SwitchInputMapper>();
+ }
+
+ MockInputHost mHost;
+ std::unique_ptr<SwitchInputMapper> mMapper;
+};
+
+TEST_F(SwitchInputMapperTest, testConfigureDevice) {
+ MockInputReportDefinition reportDef;
+ MockInputDeviceNode deviceNode;
+ deviceNode.addSwitch(SW_LID);
+ deviceNode.addSwitch(SW_CAMERA_LENS_COVER);
+
+ EXPECT_CALL(reportDef, addCollection(INPUT_COLLECTION_ID_SWITCH, 1));
+ EXPECT_CALL(reportDef, declareUsages(INPUT_COLLECTION_ID_SWITCH, _, 2))
+ .With(Args<1,2>(UnorderedElementsAre(INPUT_USAGE_SWITCH_LID,
+ INPUT_USAGE_SWITCH_CAMERA_LENS_COVER)));
+
+ EXPECT_TRUE(mMapper->configureInputReport(&deviceNode, &reportDef));
+}
+
+TEST_F(SwitchInputMapperTest, testConfigureDevice_noSwitches) {
+ MockInputReportDefinition reportDef;
+ MockInputDeviceNode deviceNode;
+
+ EXPECT_CALL(reportDef, addCollection(_, _)).Times(0);
+ EXPECT_CALL(reportDef, declareUsages(_, _, _)).Times(0);
+
+ EXPECT_FALSE(mMapper->configureInputReport(&deviceNode, &reportDef));
+}
+
+TEST_F(SwitchInputMapperTest, testProcessInput) {
+ MockInputReportDefinition reportDef;
+ MockInputDeviceNode deviceNode;
+ deviceNode.addSwitch(SW_LID);
+
+ EXPECT_CALL(reportDef, addCollection(_, _));
+ EXPECT_CALL(reportDef, declareUsages(_, _, _));
+
+ mMapper->configureInputReport(&deviceNode, &reportDef);
+
+ MockInputReport report;
+ EXPECT_CALL(reportDef, allocateReport())
+ .WillOnce(Return(&report));
+
+ {
+ // Test two switch events in order
+ InSequence s;
+ EXPECT_CALL(report, setBoolUsage(INPUT_COLLECTION_ID_SWITCH, INPUT_USAGE_SWITCH_LID, 1, 0));
+ EXPECT_CALL(report, reportEvent(_));
+ EXPECT_CALL(report, setBoolUsage(INPUT_COLLECTION_ID_SWITCH, INPUT_USAGE_SWITCH_LID, 0, 0));
+ EXPECT_CALL(report, reportEvent(_));
+ }
+
+ InputEvent events[] = {
+ {0, EV_SW, SW_LID, 1},
+ {1, EV_SYN, SYN_REPORT, 0},
+ {2, EV_SW, SW_LID, 0},
+ {3, EV_SYN, SYN_REPORT, 0},
+ };
+ for (auto e : events) {
+ mMapper->process(e);
+ }
+}
+
+} // namespace tests
+} // namespace android
+
diff --git a/tests/input/evdev/TestHelpers.cpp b/tests/input/evdev/TestHelpers.cpp
index 63b579e..9898a6f 100644
--- a/tests/input/evdev/TestHelpers.cpp
+++ b/tests/input/evdev/TestHelpers.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "TestHelpers"
#define LOG_NDEBUG 0
+#include "TestHelpers.h"
+
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -26,8 +28,6 @@
#include <utils/Log.h>
-#include "TestHelpers.h"
-
namespace android {
static const char kTmpDirTemplate[] = "/data/local/tmp/XXXXXX";
diff --git a/tests/vehicle/Android.mk b/tests/vehicle/Android.mk
new file mode 100644
index 0000000..eb41725
--- /dev/null
+++ b/tests/vehicle/Android.mk
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2015 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)
+
+# Build native tests.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ vehicle_tests.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libhardware \
+
+LOCAL_CFLAGS += -Wall -Wextra
+
+LOCAL_MODULE:= vehicle_tests
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_NATIVE_TEST)
+
+# Build HAL command line utility.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := vehicle-hal-tool.c
+LOCAL_MODULE := vehicle-hal-tool
+LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SHARED_LIBRARIES := libcutils libhardware liblog
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/vehicle/README b/tests/vehicle/README
new file mode 100644
index 0000000..b8fc7d4
--- /dev/null
+++ b/tests/vehicle/README
@@ -0,0 +1,73 @@
+What does this document tell?
+
+This document details how to use the vehicle service if you are implementhing
+HAL. It lists the various places to look for code and how to build and test the
+code on your own dev device.
+
+This code also provides a simple command line utility for the target to test the
+vehicle HAL.
+
+What is the code?
+
+The code is split into folowing logical components:
+a) hardware/libhardware/include/hardware/vehicle.h - this is the main HAL
+interface that will be required to be implemented by the OEMs. It includes all
+documentation necessary to understand what vehicle subsystems are exposed,
+various units, capabilities and any other relevant details about the HAL design
+itself.
+
+b) hardware/libhardware/modules/vehicle/vehicle.c
+This is a reference implementation for the OEMs to have a peek into getting
+started with a barebones structure. There are implementation for each of the
+critical HAL functions such as, get(), set() and subscribe().
+
+c) hardware/libhardware/tests/vehicle/vehicle_test.cpp & vehicle_test_fixtures.h
+These are native tests that can be run on the target to validate basic
+features of HAL implementation. Things such as loading of HAL and
+basic functions are implemented (by check if the returned functions are not NULL
+pointers) can be asserted. It also checks if the subscribe function is doing its
+job by spitting out data at continuous intervals and printed on the stdout.
+
+d) hardware/libhardware/tests/vehicle/vehicle-hal-tool.c
+This tool will provide you with a simple utility which can set commands to the
+HAL such as:
+i) Getting a property (and printing its value).
+ii) Setting a property (and the HAL will take some setting action).
+iii) Subscribe to a property (and the HAL should send you values at some certain
+intevals).
+
+See the usage() function in vehicle-hal-tool.c for details on how to use the
+binary.
+
+How to build and run?
+
+You can build everything by issuing the following from the top of directory. It
+is assumed that you have done a first run of make from the top level so that
+intermediates are generated.
+
+$ croot
+$ mmm hardware/libhardware
+
+This will generate the following binaries that we care about:
+i) out/target/product/XXX/system/lib/hw/vehicle.default.so
+ii) out/target/product/XXX/data/nativetest/vehicle_tests
+iii) out/target/product/XXX/system/bin/vehicle-hal-tool
+
+The location for the first shared library would be:
+$ adb push out/target/product/XXX/system/lib/hw/vehicle.default.so
+/system/lib/hw
+You can also use 'adb sync' if you like, although this is the easiest least
+hassle way of putting it in place.
+
+The second binary is a native test - which is nothing but an executable for the
+target device. You can load it anywhere in your /data directory and run it as:
+$ adb push out/target/product/XXX/data/nativetest/vehicle_tests
+/data/tmp/vehicle_tests
+$ adb shell
+$ ./data/tmp/vehicle_tests
+<...output should be spitted with passing tests for atleast the reference
+implementation ...>
+
+The last binary is the command line tool, to push the binary on your target do:
+$ adb push out/target/product/XXX/system/bin/vehicle-hal-tool
+/data/tmp/vehicle-hal-tool
diff --git a/tests/vehicle/vehicle-hal-tool.c b/tests/vehicle/vehicle-hal-tool.c
new file mode 100755
index 0000000..d10a7b9
--- /dev/null
+++ b/tests/vehicle/vehicle-hal-tool.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2015 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 "vehicle-hal-tool"
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <hardware/hardware.h>
+#include <hardware/vehicle.h>
+
+#include <cutils/log.h>
+
+void usage() {
+ printf("Usage: "
+ "./vehicle-hal-tool [-l] [-m -p -t [-v]]\n"
+ "-l - List properties\n"
+ "-m - Mode (cannot be used with -l). Accepted strings: get, set or sub.\n"
+ "-p - Property (only used with -m)\n"
+ "-t - Type (only used with -m)\n"
+ "-w - Wait time in seconds (only used with -m set to sub)\n"
+ "-v - Value to which vehicle_prop_value is set\n"
+ "Depending on the type pass the value:\n"
+ "Int: pass a quoted integer\n"
+ "Float: pass a quoted float\n"
+ "Int array: pass a quoted space delimited int array, eg: \"1 2 3 4\" for\n:"
+ "setting int32_array's all 4 elements (see VEHICLE_VALUE_TYPE_INT32_VEC4\n"
+ "String: pass a normal string\n\n"
+ "The configurations to use the tool are as follows:\n"
+ "List Properties\n"
+ "---------------\n"
+ "./vehicle-hal-tool -l \n"
+ "Lists the various properties defined in HAL implementation. Use this to check if "
+ "the HAL implementation is correctly set up and exposing the capabilities correctly.\n"
+
+ "Get Properties\n"
+ "---------------\n"
+ "./vehicle-hal-tool -m get -p <prop> -t <type> [-v <vehicle_prop_value>]\n"
+ "Example: ./vehicle-hal-tool -m get -p 1028 -t 3 # VEHICLE_PROPERTY_DRIVING_STATUS\n"
+ "./vehicle-hal-tool -m get -p 257 -t 1 # VEHICLE_PROPERTY_INFO_MAKE\n"
+ "./vehicle-hal-tool -m get -p 2049 -t 19 -v \"3 0 0 0\"\n"
+ " # VEHICLE_PROPERTY_RADIO_PRESET\n"
+ "with preset value set to 3.\n\n"
+ "Set properties\n"
+ "--------------\n"
+ "./vehicle-hal-tool -m set -p 10 -t 1 -v random_property\n"
+ "Set properties may not be applicable to most properties\n\n"
+ "Subscribe properties\n"
+ "--------------------\n"
+ "Subscribes to be notified about a property change (depending on whether\n"
+ "it is a on change property or a continuous property) for seconds provided\n"
+ "as -w paramter.\n"
+ "./vehicle-hal-tool -m sub -p 1028 -w 10\n"
+ );
+}
+
+void list_all_properties(vehicle_hw_device_t *device) {
+ int num_configs = -1;
+ const vehicle_prop_config_t *configs = device->list_properties(device, &num_configs);
+ if (num_configs < 0) {
+ printf("List configs error. %d", num_configs);
+ exit(1);
+ }
+
+ printf("Listing configs\n--------------------\n");
+ int i = 0;
+ for (i = 0; i < num_configs; i++) {
+ const vehicle_prop_config_t *config_temp = configs + i;
+ printf("Property ID: %d\n"
+ "Property config_flags: %d\n"
+ "Property change mode: %d\n"
+ "Property min sample rate: %f\n"
+ "Property max sample rate: %f\n",
+ config_temp->prop, config_temp->config_flags, config_temp->change_mode,
+ config_temp->min_sample_rate, config_temp->max_sample_rate);
+ }
+}
+
+void get_property(
+ vehicle_hw_device_t *device, int32_t property, int32_t type, char *value_string) {
+ vehicle_prop_value_t *data = (vehicle_prop_value_t *) malloc (sizeof(vehicle_prop_value_t));
+
+ // Parse the string according to type.
+ if (value_string != NULL && strlen(value_string) > 0) {
+ switch (type) {
+ case VEHICLE_VALUE_TYPE_INT32:
+ sscanf(value_string, "%d", &(data->value.int32_value));
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC4:
+ {
+ int32_t vec[4];
+ sscanf(value_string, "%d %d %d %d", &vec[0], &vec[1], &vec[2], &vec[3]);
+ memcpy(data->value.int32_array, vec, sizeof(vec));
+ break;
+ }
+ default:
+ printf("%s Setting value type not supported: %d\n", __func__, type);
+ exit(1);
+ }
+ }
+
+ data->prop = property;
+ int ret_code = device->get(device, data);
+ if (ret_code != 0) {
+ printf("Cannot get property: %d\n", ret_code);
+ exit(1);
+ }
+
+ // We simply convert the data into the type mentioned by the result of the
+ // get call.
+ printf("Get output\n------------\n");
+ switch (data->value_type) {
+ case VEHICLE_VALUE_TYPE_FLOAT:
+ printf("Value type: FLOAT\nValue: %f\n", data->value.float_value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32:
+ printf("Value type: INT32\nValue: %d\n", data->value.int32_value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT64:
+ printf("Value type: INT64\nValue: %" PRId64 "\n", data->value.int64_value);
+ break;
+ case VEHICLE_VALUE_TYPE_BOOLEAN:
+ printf("Value type: BOOLEAN\nValue: %d\n", data->value.boolean_value);
+ break;
+ case VEHICLE_VALUE_TYPE_STRING:
+ printf("Value type: STRING\n Size: %d\n", data->value.str_value.len);
+ // This implementation only supports ASCII.
+ char *ascii_out = (char *) malloc((data->value.str_value.len + 1) * sizeof(char));
+ memcpy(ascii_out, data->value.str_value.data, data->value.str_value.len);
+ ascii_out[data->value.str_value.len] = '\0';
+ printf("Value: %s\n", ascii_out);
+ break;
+ case VEHICLE_VALUE_TYPE_ZONED_FLOAT:
+ printf("Value type: ZONED_FLOAT\nZone: %d\n", data->value.zoned_float_value.zone);
+ printf("Value type: ZONED_FLOAT\nValue: %f\n", data->value.zoned_float_value.value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC3:
+ printf("Value type: INT32_VEC3\nValue[0]: %d\n", data->value.int32_array[0]);
+ printf("Value type: INT32_VEC3\nValue[1]: %d\n", data->value.int32_array[1]);
+ printf("Value type: INT32_VEC3\nValue[2]: %d\n", data->value.int32_array[2]);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC4:
+ printf("Value type: INT32_VEC4\nValue[0]: %d\n", data->value.int32_array[0]);
+ printf("Value type: INT32_VEC4\nValue[1]: %d\n", data->value.int32_array[1]);
+ printf("Value type: INT32_VEC4\nValue[2]: %d\n", data->value.int32_array[2]);
+ printf("Value type: INT32_VEC4\nValue[3]: %d\n", data->value.int32_array[3]);
+ break;
+ default:
+ printf("Value type not yet handled: %d.\n", data->value_type);
+ }
+ free(data);
+}
+
+void set_property(vehicle_hw_device_t *device,
+ int32_t property,
+ int32_t type,
+ char *data) {
+ vehicle_prop_value_t vehicle_data;
+ vehicle_data.prop = property;
+ vehicle_data.value_type = type;
+ int32_t zone = 0;
+ float value = 0.0;
+ switch (type) {
+ case VEHICLE_VALUE_TYPE_FLOAT:
+ vehicle_data.value.float_value = atof(data);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32:
+ vehicle_data.value.int32_value = atoi(data);
+ break;
+ case VEHICLE_VALUE_TYPE_INT64:
+ vehicle_data.value.int64_value = atoi(data);
+ break;
+ case VEHICLE_VALUE_TYPE_BOOLEAN:
+ vehicle_data.value.boolean_value = atoi(data);
+ break;
+ case VEHICLE_VALUE_TYPE_STRING:
+ // TODO: Make the code generic to UTF8 characters.
+ vehicle_data.value.str_value.len = strlen(data);
+ vehicle_data.value.str_value.data =
+ (uint8_t *) malloc (strlen(data) * sizeof(uint8_t));
+ memcpy(vehicle_data.value.str_value.data, data, strlen(data) + 1);
+ break;
+ case VEHICLE_VALUE_TYPE_ZONED_FLOAT:
+ sscanf(data, "%d %f", &zone, &value);
+ vehicle_data.value.zoned_float_value.zone = zone;
+ vehicle_data.value.zoned_float_value.value = value;
+ printf("Value type: ZONED_FLOAT\nZone: %d\n", vehicle_data.value.zoned_float_value.zone);
+ printf("Value type: ZONED_FLOAT\nValue: %f\n", vehicle_data.value.zoned_float_value.value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC2:
+ sscanf(data, "%d %d", &vehicle_data.value.int32_array[0],
+ &vehicle_data.value.int32_array[1]);
+ printf("Setting: Value type INT32_VEC2: %d %d\n",
+ vehicle_data.value.int32_array[0],
+ vehicle_data.value.int32_array[1]);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC3:
+ sscanf(data, "%d %d %d", &vehicle_data.value.int32_array[0],
+ &vehicle_data.value.int32_array[1],
+ &vehicle_data.value.int32_array[2]);
+ printf("Setting: Value type INT32_VEC3: %d %d %d\n",
+ vehicle_data.value.int32_array[0],
+ vehicle_data.value.int32_array[1],
+ vehicle_data.value.int32_array[2]);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC4:
+ sscanf(data, "%d %d %d %d", &vehicle_data.value.int32_array[0],
+ &vehicle_data.value.int32_array[1],
+ &vehicle_data.value.int32_array[2],
+ &vehicle_data.value.int32_array[3]);
+ printf("Setting: Value type INT32_VEC4: %d %d %d %d\n",
+ vehicle_data.value.int32_array[0],
+ vehicle_data.value.int32_array[1],
+ vehicle_data.value.int32_array[2],
+ vehicle_data.value.int32_array[3]);
+ break;
+ default:
+ printf("set_property: Value type not yet handled: %d\n", type);
+ exit(1);
+ }
+ printf("Property id: %d\n", vehicle_data.prop);
+ int ret_code = device->set(device, &vehicle_data);
+ if (ret_code != 0) {
+ printf("Cannot set property: %d\n", ret_code);
+ exit(1);
+ }
+}
+
+int vehicle_event_callback(const vehicle_prop_value_t *event_data) {
+ // Print what we got.
+ printf("Got some value from callback property: %d\n", event_data->prop);
+ printf("Timestamp: %" PRId64 "\n", event_data->timestamp);
+ char *ascii_out;
+ switch (event_data->value_type) {
+ case VEHICLE_VALUE_TYPE_FLOAT:
+ printf("Float value: %f\n", event_data->value.float_value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32:
+ printf("int32 value: %d\n", event_data->value.int32_value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT64:
+ printf("int64 value: %" PRId64 "\n", event_data->value.int64_value);
+ break;
+ case VEHICLE_VALUE_TYPE_BOOLEAN:
+ printf("bool value: %d\n", event_data->value.boolean_value);
+ break;
+ case VEHICLE_VALUE_TYPE_STRING:
+ // TODO: Make the code generic to UTF8 characters.
+ ascii_out = (char *) malloc ((event_data->value.str_value.len + 1) * sizeof(char));
+ memcpy(ascii_out, event_data->value.str_value.data, event_data->value.str_value.len);
+ ascii_out[event_data->value.str_value.len] = '\0';
+ printf("Ascii value: %s\n", ascii_out);
+ break;
+ case VEHICLE_VALUE_TYPE_ZONED_FLOAT:
+ printf("Value type: ZONED_FLOAT\nZone: %d\n", event_data->value.zoned_float_value.zone);
+ printf("Value type: ZONED_FLOAT\nValue: %f\n", event_data->value.zoned_float_value.value);
+ break;
+ case VEHICLE_VALUE_TYPE_INT32_VEC4:
+ printf("Value type: INT32_VEC4\nValue[0]: %d Value[1] %d Value[2] %d Value[3] %d\n",
+ event_data->value.int32_array[0], event_data->value.int32_array[1],
+ event_data->value.int32_array[2], event_data->value.int32_array[3]);
+ break;
+ default:
+ printf("vehicle_event_callback: Value type not yet handled: %d\n",
+ event_data->value_type);
+ exit(1);
+ }
+ return 0;
+}
+int vehicle_error_callback(int32_t error_code, int32_t property, int32_t operation) {
+ // Print what we got.
+ printf("Error code obtained: %d\n", error_code);
+ return 0;
+}
+void subscribe_to_property(
+ vehicle_hw_device_t *device,
+ int32_t prop,
+ float sample_rate,
+ uint32_t wait_in_seconds) {
+ // Init the device with a callback.
+ device->init(device, vehicle_event_callback, vehicle_error_callback);
+ int ret_code = device->subscribe(device, prop, 0, 0);
+ if (ret_code != 0) {
+ printf("Could not subscribe: %d\n", ret_code);
+ exit(1);
+ }
+
+ // Callbacks will happen on one of the threads created by the HAL hence we
+ // can simply sleep here and see the output.
+ sleep(wait_in_seconds);
+
+ // Unsubscribe and uninit.
+ ret_code = device->unsubscribe(device, prop);
+ if (ret_code != 0) {
+ printf("Error unsubscribing the HAL, still continuining to uninit HAL ...");
+ }
+
+ ret_code = device->release(device);
+ if (ret_code != 0) {
+ printf("Error uniniting HAL, exiting anyways.");
+ }
+}
+
+int main(int argc, char* argv[]) {
+ // Open the vehicle module and just ask for the list of properties.
+ const hw_module_t *hw_module = NULL;
+ int ret_code = hw_get_module(VEHICLE_HARDWARE_MODULE_ID, &hw_module);
+ if (ret_code != 0) {
+ printf("Cannot open the hw module. Does the HAL exist? %d\n", ret_code);
+ return -1;
+ }
+
+ vehicle_module_t *vehicle_module = (vehicle_module_t *)(hw_module);
+ hw_device_t *device = NULL;
+ ret_code = vehicle_module->common.methods->open(hw_module, NULL, &device);
+ if (!device) {
+ printf("Cannot open the hw device: %d\n", ret_code);
+ return -1;
+ }
+ vehicle_hw_device_t *vehicle_device = (vehicle_hw_device_t *) (device);
+ printf("HAL Loaded!\n");
+
+ // If this is a list properties command - we check for -l command.
+ int list_properties = 0;
+ // Type of the property (see #defines in vehicle.h).
+ int property = -1;
+ // Type of the value of the property (see enum vehicle_value_type).
+ int type = -1;
+ // Whether the mode is "get" or "set".
+ char mode[100] = "";
+ // Actual value as a string representation (supports only PODs for now).
+ // TODO: Support structures and complex types in the tool.
+ char value[100] = "";
+ // Wait time for the subscribe type of calls.
+ // We keep a default in case the user does not specify one.
+ int wait_time_in_sec = 10;
+ // Sample rate for subscribe type of calls.
+ // Default value is 0 for onchange type of properties.
+ int sample_rate = 0;
+ // Int array string which represents the vehicle_value_t in array of
+ // numbers. See vehicle_prop_value_t.value.int32_array.
+ char int_array_string[1000]; int_array_string[0] = '\0';
+
+ int opt;
+ //TODO allow passing zone
+ while ((opt = getopt(argc, argv, "lm:p:t:v:w:s:")) != -1) {
+ switch (opt) {
+ case 'l':
+ list_properties = 1;
+ break;
+ case 'm':
+ strcpy(mode, optarg);
+ break;
+ case 'p':
+ property = atoi(optarg);
+ break;
+ case 't':
+ type = atoi(optarg);
+ break;
+ case 'v':
+ strcpy(value, optarg);
+ break;
+ case 'w':
+ wait_time_in_sec = atoi(optarg);
+ break;
+ case 's':
+ sample_rate = atoi(optarg);
+ break;
+ }
+ }
+
+ // We should have atleast one of list properties or mode (for get or set).
+ if (!list_properties &&
+ !(!strcmp(mode, "get") || !strcmp(mode, "set") || !strcmp(mode, "sub"))) {
+ usage();
+ exit(1);
+ }
+
+ if (list_properties) {
+ printf("Listing properties...\n");
+ list_all_properties(vehicle_device);
+ } else if (!strcmp(mode, "get")) {
+ printf("Getting property ...\n");
+ if (property == -1) {
+ printf("Use -p to pass a valid Property.\n");
+ usage();
+ exit(1);
+ }
+
+ int32_t int_array_list[4];
+ int count = -1;
+ if (strlen(int_array_string) > 0) {
+ count = sscanf(int_array_string, "%d%d%d%d",
+ &int_array_list[0], &int_array_list[1], &int_array_list[2], &int_array_list[3]);
+ }
+
+ get_property(vehicle_device, property, type, value);
+ } else if (!strcmp(mode, "set")) {
+ printf("Setting property ...\n");
+ if (property == -1 || type == -1) {
+ printf("Use -p to pass a valid Property and -t to pass a valid Type.\n");
+ usage();
+ exit(1);
+ }
+ set_property(vehicle_device, property, type, value);
+ } else if (!strcmp(mode, "sub")) {
+ printf("Subscribing property ...\n");
+ if (property == -1 || wait_time_in_sec <= 0) {
+ printf("Use -p to pass a valid property and -w to pass a valid wait time(s)\n");
+ usage();
+ exit(1);
+ }
+ subscribe_to_property(vehicle_device, property, sample_rate, wait_time_in_sec);
+ }
+ return 0;
+}
diff --git a/tests/vehicle/vehicle_test_fixtures.h b/tests/vehicle/vehicle_test_fixtures.h
new file mode 100644
index 0000000..15cafaa
--- /dev/null
+++ b/tests/vehicle/vehicle_test_fixtures.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 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_HAL_VEHICLE_TEST_
+#define __ANDROID_HAL_VEHICLE_TEST_
+
+#include <gtest/gtest.h>
+#include <hardware/hardware.h>
+#include <hardware/vehicle.h>
+
+namespace tests {
+
+static const uint64_t kVersion = HARDWARE_DEVICE_API_VERSION_2(1, 0, 1);
+
+class VehicleModule : public testing::Test {
+public:
+ VehicleModule() :
+ vehicle_module_(NULL) {}
+ ~VehicleModule() {}
+protected:
+ virtual void SetUp() {
+ const hw_module_t *hw_module = NULL;
+ ASSERT_EQ(0, hw_get_module(VEHICLE_HARDWARE_MODULE_ID, &hw_module))
+ << "Can't get vehicle module";
+ ASSERT_TRUE(NULL != hw_module)
+ << "hw_get_module didn't return a valid hardware module";
+
+ vehicle_module_ = reinterpret_cast<const vehicle_module_t*>(hw_module);
+ }
+ const vehicle_module_t* vehicle_module() { return vehicle_module_; }
+private:
+ const vehicle_module_t* vehicle_module_;
+};
+
+
+int VehicleEventCallback(const vehicle_prop_value_t* event_data) {
+ // Print what we got.
+ std::cout << "got some value from callback: "
+ << event_data->prop
+ << " uint32 value: "
+ << event_data->value.int32_value << "\n";
+ return 0;
+}
+
+int VehicleErrorCallback(int32_t error_code, int32_t property, int32_t operation) {
+ // Do nothing.
+ return 0;
+}
+
+class VehicleDevice : public VehicleModule {
+public:
+ VehicleDevice() :
+ vehicle_device_(NULL) {}
+ ~VehicleDevice() {}
+protected:
+ virtual void SetUp() {
+ VehicleModule::SetUp();
+ hw_device_t *device = NULL;
+ ASSERT_TRUE(NULL != vehicle_module()->common.methods->open)
+ << "Vehicle open() is unimplemented";
+ ASSERT_EQ(0, vehicle_module()->common.methods->open(
+ (const hw_module_t*)vehicle_module(), NULL, &device))
+ << "Can't open vehicle device";
+ ASSERT_TRUE(NULL != device)
+ << "Vehicle open() returned a NULL device";
+ ASSERT_EQ(kVersion, device->version)
+ << "Unsupported version";
+ vehicle_device_ = reinterpret_cast<vehicle_hw_device_t*>(device);
+ }
+ vehicle_hw_device_t* vehicle_device() { return vehicle_device_; }
+ vehicle_event_callback_fn callback_fn() {
+ return VehicleEventCallback;
+ }
+ vehicle_error_callback_fn error_fn() {
+ return VehicleErrorCallback;
+ }
+
+ private:
+ vehicle_hw_device_t* vehicle_device_;
+};
+
+} // namespace tests
+
+#endif // __ANDROID_HAL_VEHICLE_TEST_
diff --git a/tests/vehicle/vehicle_tests.cpp b/tests/vehicle/vehicle_tests.cpp
new file mode 100644
index 0000000..4c15570
--- /dev/null
+++ b/tests/vehicle/vehicle_tests.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 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 <gtest/gtest.h>
+#include "vehicle_test_fixtures.h"
+#include "hardware/vehicle.h"
+
+namespace tests {
+
+// Check if list_properties command exists.
+TEST_F(VehicleDevice, isThereListProperties) {
+ ASSERT_TRUE(NULL != vehicle_device()->list_properties)
+ << "list_properties() function is not implemented";
+ std::cout << "Test succeeds.\n";
+}
+
+// HAL should provide atleast one property. The output of this command should be
+// used to verify the vailidity of the function.
+TEST_F(VehicleDevice, listPropertiesMoreThanOne) {
+ vehicle_prop_config_t const* config;
+ int num_configs = -1;
+ config = vehicle_device()->list_properties(vehicle_device(), &num_configs);
+ ASSERT_TRUE(num_configs > -1) << "list_properties() call failed.";
+ ASSERT_TRUE(num_configs > 0) << "list_properties() returned zero items.";
+ std::cout << "Number of properties reported: " << num_configs << "\n";
+ for (int i = 0; i < num_configs; i++) {
+ // Print each of the properties.
+ const vehicle_prop_config_t& config_temp = config[i];
+ std::cout << "Property ID: " << config_temp.prop << "\n";
+ std::cout << "Property flags: " << config_temp.config_flags << "\n";
+ std::cout << "Property change mode: " << config_temp.change_mode << "\n";
+ std::cout << "Property min sample rate: " << config_temp.min_sample_rate << "\n";
+ std::cout << "Property max sample rate: " << config_temp.max_sample_rate << "\n\n";
+ }
+}
+
+// Test get() command.
+// The fields are hardcoded in the dummy implementation and here.
+TEST_F(VehicleDevice, getDriveState) {
+ vehicle_prop_value_t data;
+ data.prop = VEHICLE_PROPERTY_DRIVING_STATUS;
+ // Set drive_state field to EINVAL so that we can check that its valid when
+ // it comes back.
+ data.value_type = -EINVAL;
+ data.value.driving_status = -EINVAL;
+ vehicle_device()->get(vehicle_device(), &data);
+
+ // Check that retured values are not invalid.
+ ASSERT_NE(data.value_type, -EINVAL) << "Drive state value type should be integer.";
+ ASSERT_NE(data.value.driving_status, -EINVAL) << "Driving status should be positive.";
+
+ std::cout << "Driving status value type: " << data.value_type << "\n"
+ << "Driving status: " << data.value.driving_status << "\n";
+}
+
+// Test the workflows for subscribe and init/release.
+// Subscribe will return error before init() is called or after release() is
+// called.
+TEST_F(VehicleDevice, initTest) {
+ // Test that init on a new device works. When getting an instance, we are
+ // already calling 'open' on the device.
+ int ret_code =
+ vehicle_device()->init(vehicle_device(), callback_fn(), error_fn());
+ ASSERT_EQ(ret_code, 0) << "ret code: " << ret_code;
+
+ // Trying to init again should return an error.
+ ret_code = vehicle_device()->init(vehicle_device(), callback_fn(), error_fn());
+ ASSERT_EQ(ret_code, -EEXIST) << "ret code: " << ret_code;
+
+ // Uninit should always return 0.
+ ret_code = vehicle_device()->release(vehicle_device());
+ ASSERT_EQ(ret_code, 0) << "ret code: " << ret_code;
+
+ // We should be able to init again.
+ ret_code = vehicle_device()->init(vehicle_device(), callback_fn(), error_fn());
+ ASSERT_EQ(ret_code, 0) << "ret code: " << ret_code;
+
+ // Finally release.
+ ret_code = vehicle_device()->release(vehicle_device());
+ ASSERT_EQ(ret_code, 0) << "ret_code: " << ret_code;
+}
+
+// Test that subscribe works.
+// We wait for 10 seconds while which the vehicle.c can post messages from
+// within it's own thread.
+TEST_F(VehicleDevice, subscribeTest) {
+ // If the device is not init subscribe should fail off the bat.
+ int ret_code = vehicle_device()->subscribe(vehicle_device(), VEHICLE_PROPERTY_DRIVING_STATUS,
+ 0, 0);
+ ASSERT_EQ(ret_code, -EINVAL) << "Return code is: " << ret_code;
+
+ // Let's init the device.
+ ret_code = vehicle_device()->init(vehicle_device(), callback_fn(), error_fn());
+ ASSERT_EQ(ret_code, 0) << "Return code is: " << ret_code;
+
+ // Subscribe should now go through.
+ ret_code = vehicle_device()->subscribe(vehicle_device(), VEHICLE_PROPERTY_DRIVING_STATUS, 0, 0);
+ ASSERT_EQ(ret_code, 0) << "Return code is: " << ret_code;
+
+ // We should start getting some messages thrown from the callback. Let's
+ // wait for 20 seconds before unsubscribing.
+ std::cout << "Sleeping for 20 seconds.";
+ sleep(20);
+ std::cout << "Waking from sleep.";
+
+ // This property does not exist, so we should get -EINVAL.
+ ret_code = vehicle_device()->unsubscribe(vehicle_device(), VEHICLE_PROPERTY_INFO_VIN);
+ ASSERT_EQ(ret_code, -EINVAL) << "Return code is: " << ret_code;
+
+ // This property exists, so we should get a success return code - also this
+ // will be a blocking call.
+ ret_code = vehicle_device()->unsubscribe(vehicle_device(), VEHICLE_PROPERTY_DRIVING_STATUS);
+ ASSERT_EQ(ret_code, 0) << "Return code is: " << ret_code;
+}
+
+} // namespace tests