Revert "DO NOT MERGE ANYWHERE Add new interface for sensor physical data" am: 8b48359616  -s ours am: 500b648def  -s ours am: 0a37154ad7  -s ours
am: 0716cc0e90  -s ours

* commit '0716cc0e90824b050787e28bfda384f0603d8a9d':
  Revert "DO NOT MERGE ANYWHERE Add new interface for sensor physical data"
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/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 bf09e23..27cef37 100644
--- a/include/hardware/keymaster_defs.h
+++ b/include/hardware/keymaster_defs.h
@@ -511,7 +511,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/vehicle.h b/include/hardware/vehicle.h
new file mode 100644
index 0000000..267a910
--- /dev/null
+++ b/include/hardware/vehicle.h
@@ -0,0 +1,1492 @@
+/*
+ * 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_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
+ * @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
+ * @data_member hvac.fan_direction
+ * @data_enum TODO
+ */
+#define VEHICLE_PROPERTY_HVAC_FAN_DIRECTION                         (0x00000501)
+
+/**
+ * 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
+ * @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
+ * @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
+ * @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
+ * @data_member hvac.ac_on
+ */
+#define VEHICLE_PROPERTY_HVAC_AC_ON                                 (0x00000505)
+
+/**
+ * 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
+ * @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 stream.
+ *
+ * Data type looks like:
+ *   int32_array[0] : stream number (not bit flag) like VEHICLE_AUDIO_STREAM0.
+ *   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
+ * @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 volume.
+ *   int32_array[0] : stream number (not bit flag) like VEHICLE_AUDIO_STREAM0.
+ *   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
+ * @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 application contexts that will be sent through the physical stream. Flag
+ *                    is defined in vehicle_app_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
+* @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 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
+ * @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,
+};
+
+/**
+ * Property to share currently active application 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_APP_CONTEXT                        (0x00000B00)
+/**
+ * Flags to tell the current application context. The same flag is used in
+ */
+enum vehicle_app_context_flag {
+    /** Music playback is currently active. */
+    VEHICLE_APP_CONTEXT_MUSIC_FLAG = 0x1,
+    /** Navigation is currently running. */
+    VEHICLE_APP_CONTEXT_NAVIGATION_FLAG = 0x2,
+    /** Voice command session is currently running. */
+    VEHICLE_APP_CONTEXT_VOICE_COMMAND_FLAG = 0x4,
+    /** Voice call is currently active. */
+    VEHICLE_APP_CONTEXT_CALL_FLAG = 0x8,
+    /** Alarm is active. This may be only used in VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY. */
+    VEHICLE_APP_CONTEXT_ALARM_FLAG = 0x10,
+    /**
+     * Notification sound is active. This may be only used in VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY.
+     */
+    VEHICLE_APP_CONTEXT_NOTIFICATION_FLAG = 0x20,
+    /**
+     * Context unknown. Only used for VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY to represent default
+     * stream for unknown contents.
+     */
+    VEHICLE_APP_CONTEXT_UNKNOWN_FLAG = 0x40,
+};
+
+/**
+ *  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                       (0xf0000000)
+/** @range_end */
+#define VEHICLE_PROPERTY_CUSTOM_END                         (0xf7ffffff)
+
+/**
+ * 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                     (0xf8000000)
+/**
+ * @range_end
+ */
+#define VEHICLE_PROPERTY_INTERNAL_END                       (0xf8ffffff)
+
+/**
+ * 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_INT32              = 0x04,
+    VEHICLE_VALUE_TYPE_ZONED_FLOAT              = 0x05,
+    VEHICLE_VALUE_TYPE_ZONED_BOOLEAN            = 0x06,
+    VEHICLE_VALUE_TYPE_INT64                    = 0x07,
+    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,
+};
+
+/**
+ * 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_float {
+    union {
+        int32_t zone;
+        int32_t seat;
+        int32_t window;
+    };
+    float value;
+} vehicle_zoned_float_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;
+    };
+
+    /**
+     * 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 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_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_float_t zoned_float_value;
+    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 only set data->prop and HAL implementation needs to fill all entries properly.
+     * 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
+     */
+    int (*subscribe)(struct vehicle_hw_device* device, int32_t prop, float sample_rate);
+
+    /** 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..4f30d3c 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
 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/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/usbaudio/audio_hal.c b/modules/usbaudio/audio_hal.c
index 38fea86..d0d43ab 100644
--- a/modules/usbaudio/audio_hal.c
+++ b/modules/usbaudio/audio_hal.c
@@ -449,8 +449,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 +558,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 +568,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..69bfad3
--- /dev/null
+++ b/modules/vehicle/vehicle.c
@@ -0,0 +1,562 @@
+/*
+ * 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
+
+#include <errno.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) {
+    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,
+        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, 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 %ld, value_type %d", data->prop, data->timestamp,
+            data->value_type);
+    return 0;
+}
+
+static int vdev_set(vehicle_hw_device_t* device, 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) {
+    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->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) {
+    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, 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* __unused name,
+                     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/input/evdev/Android.mk b/tests/input/evdev/Android.mk
index 167cbc2..557acba 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..78fd714
--- /dev/null
+++ b/tests/vehicle/vehicle-hal-tool.c
@@ -0,0 +1,428 @@
+/*
+ * 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);
+    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;
+    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..5862972
--- /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);
+    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);
+    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