Initial InputMappers for evdev input HAL.
The previous design of the InputHost wrapper classes made it very
painful to do testing, so this change also reverts to a more classical
C++ pattern for non-copyable objects. The InputHost classes still simply
call through to the input_host_t and callbacks as before.
Updated unittests to use gmock for mocking the InputHost interactions.
Change-Id: I4b70df2c89ed48af77446b8f5b87a4bde94510bf
diff --git a/include/hardware/input.h b/include/hardware/input.h
index 969b8ce..91354aa 100644
--- a/include/hardware/input.h
+++ b/include/hardware/input.h
@@ -375,13 +375,23 @@
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,
} 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 +423,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/modules/input/evdev/Android.mk b/modules/input/evdev/Android.mk
index d3c49e7..b12867c 100644
--- a/modules/input/evdev/Android.mk
+++ b/modules/input/evdev/Android.mk
@@ -21,7 +21,9 @@
InputHub.cpp \
InputDevice.cpp \
InputDeviceManager.cpp \
- InputHost.cpp
+ InputHost.cpp \
+ InputMapper.cpp \
+ SwitchInputMapper.cpp
LOCAL_SHARED_LIBRARIES := \
libhardware_legacy \
diff --git a/modules/input/evdev/EvdevModule.cpp b/modules/input/evdev/EvdevModule.cpp
index 1171a1a..93ccd35 100644
--- a/modules/input/evdev/EvdevModule.cpp
+++ b/modules/input/evdev/EvdevModule.cpp
@@ -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,7 +46,7 @@
private:
void loop();
- InputHost mInputHost;
+ std::unique_ptr<InputHostInterface> mInputHost;
std::shared_ptr<InputDeviceManager> mDeviceManager;
std::unique_ptr<InputHub> mInputHub;
std::thread mPollThread;
@@ -53,9 +54,9 @@
static std::unique_ptr<EvdevModule> gEvdevModule;
-EvdevModule::EvdevModule(InputHost inputHost) :
+EvdevModule::EvdevModule(InputHostInterface* inputHost) :
mInputHost(inputHost),
- mDeviceManager(std::make_shared<InputDeviceManager>(mInputHost)),
+ mDeviceManager(std::make_shared<InputDeviceManager>(mInputHost.get())),
mInputHub(std::make_unique<InputHub>(mDeviceManager)) {}
void EvdevModule::init() {
@@ -97,7 +98,7 @@
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};
+ 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 883d6d4..8365386 100644
--- a/modules/input/evdev/InputDevice.cpp
+++ b/modules/input/evdev/InputDevice.cpp
@@ -32,6 +32,8 @@
#include "InputHub.h"
#include "InputDevice.h"
+#include "InputMapper.h"
+#include "SwitchInputMapper.h"
#define MSC_ANDROID_TIME_SEC 0x6
#define MSC_ANDROID_TIME_USEC 0x7
@@ -104,49 +106,83 @@
return value;
}
-static void setDeviceClasses(const InputDeviceNode* node, uint32_t* classes) {
- // 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.
- bool haveKeyboardKeys = node->hasKeyInRange(0, BTN_MISC) ||
- node->hasKeyInRange(KEY_OK, KEY_CNT);
- bool haveGamepadButtons = node->hasKeyInRange(BTN_MISC, BTN_MOUSE) ||
- node->hasKeyInRange(BTN_JOYSTICK, BTN_DIGI);
- if (haveKeyboardKeys || haveGamepadButtons) {
- *classes |= INPUT_DEVICE_CLASS_KEYBOARD;
- }
+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 (node->hasKey(BTN_MOUSE)
- && node->hasRelativeAxis(REL_X)
- && node->hasRelativeAxis(REL_Y)) {
- *classes |= INPUT_DEVICE_CLASS_CURSOR;
+ if (mDeviceNode->hasKey(BTN_MOUSE)
+ && mDeviceNode->hasRelativeAxis(REL_X)
+ && mDeviceNode->hasRelativeAxis(REL_Y)) {
+ mClasses |= INPUT_DEVICE_CLASS_CURSOR;
+ //mMappers.push_back(std::make_unique<CursorInputMapper>());
}
- // See if this is a touch pad.
+ 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 (node->hasAbsoluteAxis(ABS_MT_POSITION_X)
- && node->hasAbsoluteAxis(ABS_MT_POSITION_Y)) {
+ 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 (node->hasKey(BTN_TOUCH) || !haveGamepadButtons) {
- *classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
+ 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 (node->hasKey(BTN_TOUCH)
- && node->hasAbsoluteAxis(ABS_X)
- && node->hasAbsoluteAxis(ABS_Y)) {
- *classes != INPUT_DEVICE_CLASS_TOUCH;
+ } 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 ((node->hasAbsoluteAxis(ABS_PRESSURE) || node->hasKey(BTN_TOUCH))
- && !node->hasAbsoluteAxis(ABS_X) && !node->hasAbsoluteAxis(ABS_Y)) {
- *classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
- // Keyboard will try to claim some of the buttons but we really want to
- // reserve those so we can fuse it with the touch screen data, so just
- // take them back. Note this means an external stylus cannot also be a
- // keyboard device.
- *classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;
+ } 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.
@@ -154,11 +190,12 @@
// distinguish them from other devices such as accelerometers that also have
// absolute axes.
if (haveGamepadButtons) {
- uint32_t assumedClasses = *classes | INPUT_DEVICE_CLASS_JOYSTICK;
+ uint32_t assumedClasses = mClasses | INPUT_DEVICE_CLASS_JOYSTICK;
for (int i = 0; i < ABS_CNT; ++i) {
- if (node->hasAbsoluteAxis(i)
+ if (mDeviceNode->hasAbsoluteAxis(i)
&& getAbsAxisUsage(i, assumedClasses) == INPUT_DEVICE_CLASS_JOYSTICK) {
- *classes = assumedClasses;
+ mClasses = assumedClasses;
+ //mMappers.push_back(std::make_unique<JoystickInputMapper>());
break;
}
}
@@ -166,36 +203,40 @@
// Check whether this device has switches.
for (int i = 0; i < SW_CNT; ++i) {
- if (node->hasSwitch(i)) {
- *classes |= INPUT_DEVICE_CLASS_SWITCH;
+ if (mDeviceNode->hasSwitch(i)) {
+ mClasses |= INPUT_DEVICE_CLASS_SWITCH;
+ mMappers.push_back(std::make_unique<SwitchInputMapper>());
break;
}
}
// Check whether this device supports the vibrator.
- if (node->hasForceFeedback(FF_RUMBLE)) {
- *classes |= INPUT_DEVICE_CLASS_VIBRATOR;
+ // TODO: decide if this is necessary.
+ if (mDeviceNode->hasForceFeedback(FF_RUMBLE)) {
+ mClasses |= INPUT_DEVICE_CLASS_VIBRATOR;
+ //mMappers.push_back(std::make_unique<VibratorInputMapper>());
}
- // If the device isn't recognized as something we handle, don't monitor it.
- // TODO
-
- ALOGD("device %s classes=0x%x", node->getPath().c_str(), *classes);
+ ALOGD("device %s classes=0x%x %d mappers", mDeviceNode->getPath().c_str(), mClasses,
+ mMappers.size());
}
-EvdevDevice::EvdevDevice(InputHost host, const std::shared_ptr<InputDeviceNode>& node) :
- mHost(host), mDeviceNode(node) {
+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);
+ }
- InputBus bus = getInputBus(node);
- mInputId = mHost.createDeviceIdentifier(
- node->getName().c_str(),
- node->getProductId(),
- node->getVendorId(),
- bus,
- node->getUniqueId().c_str());
-
- InputPropertyMap propMap = mHost.getDevicePropertyMap(mInputId);
- setDeviceClasses(mDeviceNode.get(), &mClasses);
+ reportDef = mHost->createOutputReportDefinition();
+ if (mapper->configureOutputReport(mDeviceNode.get(), reportDef)) {
+ mDeviceDefinition->addReport(reportDef);
+ } else {
+ mHost->freeReportDefinition(reportDef);
+ }
+ }
}
void EvdevDevice::processInput(InputEvent& event, nsecs_t currentTime) {
@@ -260,6 +301,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 b4f3244..a379d6c 100644
--- a/modules/input/evdev/InputDevice.h
+++ b/modules/input/evdev/InputDevice.h
@@ -18,11 +18,13 @@
#define ANDROID_INPUT_DEVICE_H_
#include <memory>
+#include <vector>
#include <utils/Timers.h>
#include "InputHost.h"
#include "InputHub.h"
+#include "InputMapper.h"
namespace android {
@@ -45,16 +47,22 @@
*/
class EvdevDevice : public InputDeviceInterface {
public:
- EvdevDevice(InputHost host, const 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:
- InputHost mHost;
+ void createMappers();
+ void configureDevice();
+
+ InputHostInterface* mHost = nullptr;
std::shared_ptr<InputDeviceNode> mDeviceNode;
- InputDeviceIdentifier mInputId;
+ InputDeviceIdentifier* mInputId = nullptr;
+ InputDeviceDefinition* mDeviceDefinition = nullptr;
+ InputDeviceHandle* mDeviceHandle = nullptr;
+ std::vector<std::unique_ptr<InputMapper>> mMappers;
uint32_t mClasses = 0;
int32_t mOverrideSec = 0;
diff --git a/modules/input/evdev/InputDeviceManager.cpp b/modules/input/evdev/InputDeviceManager.cpp
index f21d6d1..46c9dfb 100644
--- a/modules/input/evdev/InputDeviceManager.cpp
+++ b/modules/input/evdev/InputDeviceManager.cpp
@@ -43,7 +43,8 @@
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 25dd912..7ffec5b 100644
--- a/modules/input/evdev/InputDeviceManager.h
+++ b/modules/input/evdev/InputDeviceManager.h
@@ -35,7 +35,7 @@
*/
class InputDeviceManager : public InputCallbackInterface {
public:
- explicit InputDeviceManager(InputHost host) :
+ explicit InputDeviceManager(InputHostInterface* host) :
mHost(host) {}
virtual ~InputDeviceManager() override = default;
@@ -45,7 +45,7 @@
virtual void onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) override;
private:
- InputHost mHost;
+ 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 74a5f8a..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,28 +42,19 @@
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);
-}
-
-InputProperty::~InputProperty() {
- mCallbacks.input_free_device_property(mHost, mProperty);
-}
-
-InputProperty::InputProperty(InputProperty&& rhs) :
- InputHostBase(rhs), mProperty(std::move(rhs.mProperty)) {
- rhs.mProperty = nullptr;
+void InputDeviceDefinition::addReport(InputReportDefinition* r) {
+ mCallbacks.input_device_definition_add_report(mHost, mDeviceDefinition, *r);
}
const char* InputProperty::getKey() const {
@@ -64,51 +65,55 @@
return mCallbacks.input_get_property_value(mHost, mProperty);
}
-InputPropertyMap::~InputPropertyMap() {
- mCallbacks.input_free_device_property_map(mHost, mMap);
-}
-
-InputPropertyMap::InputPropertyMap(InputPropertyMap&& rhs) :
- InputHostBase(rhs), mMap(std::move(rhs.mMap)) {
- rhs.mMap = nullptr;
-}
-
-InputProperty InputPropertyMap::getDeviceProperty(const char* key) const {
- 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 d6a04d9..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,8 +43,8 @@
InputHostBase(input_host_t* host, input_host_callbacks_t cb) : mHost(host), mCallbacks(cb) {}
virtual ~InputHostBase() = default;
- InputHostBase(const InputHostBase& rhs) = default;
- InputHostBase(InputHostBase&& rhs) = default;
+ InputHostBase(const InputHostBase& rhs) = delete;
+ InputHostBase(InputHostBase&& rhs) = delete;
input_host_t* mHost;
input_host_callbacks_t mCallbacks;
@@ -52,140 +52,139 @@
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;
- const char* getValue() const;
-
- // Transfers ownership of the input_property_t pointer.
- InputProperty(InputProperty&& rhs);
-
- // 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) const;
-
- // Transfers ownership of the input_property_map_t pointer.
- InputPropertyMap(InputPropertyMap&& rhs);
-
- // 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/InputMapper.cpp b/modules/input/evdev/InputMapper.cpp
new file mode 100644
index 0000000..2353a9a
--- /dev/null
+++ b/modules/input/evdev/InputMapper.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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"
+
+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..b33cb63
--- /dev/null
+++ b/modules/input/evdev/InputMapper.h
@@ -0,0 +1,82 @@
+/*
+ * 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_
+
+#include "InputHost.h"
+#include "InputHub.h"
+
+namespace android {
+
+/**
+ * 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:
+ virtual ~InputMapper() = default;
+
+ /**
+ * 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/SwitchInputMapper.cpp b/modules/input/evdev/SwitchInputMapper.cpp
new file mode 100644
index 0000000..adc2f63
--- /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 <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) {
+ ALOGD("processing switch event. type=%d code=%d value=%d",
+ event.type, event.code, event.value);
+ 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:
+ ALOGD("unknown switch event type: %d", event.type);
+ }
+}
+
+void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t 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..b3a1c05
--- /dev/null
+++ b/modules/input/evdev/SwitchInputMapper.h
@@ -0,0 +1,52 @@
+/*
+ * 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 InputDeviceNode;
+class InputReportDefinition;
+struct InputEvent;
+
+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/tests/input/evdev/Android.mk b/tests/input/evdev/Android.mk
index 544e5a8..a79de34 100644
--- a/tests/input/evdev/Android.mk
+++ b/tests/input/evdev/Android.mk
@@ -2,13 +2,17 @@
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += hardware/libhardware/modules/input/evdev
+LOCAL_C_INCLUDES += $(TOP)/external/gmock/include
LOCAL_SRC_FILES:= \
InputDevice_test.cpp \
InputHub_test.cpp \
InputMocks.cpp \
+ SwitchInputMapper_test.cpp \
TestHelpers.cpp
+LOCAL_STATIC_LIBRARIES := libgmock
+
LOCAL_SHARED_LIBRARIES := \
libinput_evdev \
liblog \
diff --git a/tests/input/evdev/InputDevice_test.cpp b/tests/input/evdev/InputDevice_test.cpp
index 123f2b8..bed05b8 100644
--- a/tests/input/evdev/InputDevice_test.cpp
+++ b/tests/input/evdev/InputDevice_test.cpp
@@ -26,9 +26,9 @@
#include <utils/Timers.h>
#include "InputDevice.h"
-#include "InputHost.h"
#include "InputHub.h"
#include "InputMocks.h"
+#include "MockInputHost.h"
// # of milliseconds to allow for timing measurements
#define TIMING_TOLERANCE_MS 25
@@ -36,26 +36,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 EvdevDeviceTest : public ::testing::Test {
protected:
- virtual void SetUp() override {
- mMockHost.reset(new MockInputHost());
- }
+ 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 void TearDown() override {
- ASSERT_TRUE(mMockHost->checkAllocations());
- }
-
- std::unique_ptr<MockInputHost> mMockHost;
+ MockInputHost mHost;
+ // Ignore uninteresting calls on the report definitions by using NiceMocks.
+ NiceMock<MockInputReportDefinition> mReportDef;
+ NiceMock<MockInputDeviceDefinition> mDeviceDef;
};
TEST_F(EvdevDeviceTest, testOverrideTime) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::make_shared<MockInputDeviceNode>();
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
ASSERT_TRUE(device != nullptr);
// Send two timestamp override events before an input event.
@@ -83,9 +98,8 @@
}
TEST_F(EvdevDeviceTest, testWrongClockCorrection) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::make_shared<MockInputDeviceNode>();
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
ASSERT_TRUE(device != nullptr);
auto now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -100,9 +114,8 @@
}
TEST_F(EvdevDeviceTest, testClockCorrectionOk) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::make_shared<MockInputDeviceNode>();
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
ASSERT_TRUE(device != nullptr);
auto now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -118,68 +131,70 @@
}
TEST_F(EvdevDeviceTest, testN7v2Touchscreen) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getElanTouchscreen());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ 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) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getButtonJack());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
}
TEST_F(EvdevDeviceTest, testN7v2HeadsetJack) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
+ // 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, registerDevice(_, _));
+
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getHeadsetJack());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
EXPECT_EQ(INPUT_DEVICE_CLASS_SWITCH, device->getInputClasses());
}
TEST_F(EvdevDeviceTest, testN7v2H2wButton) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getH2wButton());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
}
TEST_F(EvdevDeviceTest, testN7v2GpioKeys) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getGpioKeys());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
}
TEST_F(EvdevDeviceTest, testNexusPlayerGpioKeys) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getGpioKeys());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
}
TEST_F(EvdevDeviceTest, testNexusPlayerMidPowerBtn) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getMidPowerBtn());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
}
TEST_F(EvdevDeviceTest, testNexusRemote) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getNexusRemote());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ auto device = std::make_unique<EvdevDevice>(&mHost, node);
EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
}
TEST_F(EvdevDeviceTest, testAsusGamepad) {
- InputHost host = {mMockHost.get(), kTestCallbacks};
auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getAsusGamepad());
- auto device = std::make_unique<EvdevDevice>(host, node);
+ 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/InputMocks.cpp b/tests/input/evdev/InputMocks.cpp
index c316075..f4a341a 100644
--- a/tests/input/evdev/InputMocks.cpp
+++ b/tests/input/evdev/InputMocks.cpp
@@ -1,104 +1,7 @@
#include "InputMocks.h"
-// Private test definitions of opaque HAL structs
-
-// Not used
-struct input_property_map {};
-
-// Holds the key and value from the mock host's PropertyMap
-struct input_property {
- android::String8 key;
- android::String8 value;
-};
-
namespace android {
-bool MockInputHost::checkAllocations() const {
- bool ret = true;
- if (mMapAllocations != 0) {
- ALOGE("Leaked %d device property map allocations", mMapAllocations);
- ret = false;
- }
- for (auto entry : mPropertyAllocations) {
- if (entry.second != 0) {
- ALOGE("Leaked %d property allocation for %s", entry.second, entry.first.c_str());
- ret = false;
- }
- }
- return ret;
-}
-
-input_device_identifier_t* MockInputHost::createDeviceIdentifier(
- const char* name, int32_t product_id, int32_t vendor_id,
- input_bus_t bus, const char* unique_id) {
- mDeviceId.reset(new input_device_identifier_t{
- .name = name,
- .productId = product_id,
- .vendorId = vendor_id,
- .bus = bus,
- .uniqueId = unique_id
- });
- // Just return the raw pointer. We don't have a method for deallocating
- // device identifiers yet, and they should exist throughout the lifetime of
- // the input process for now.
- return mDeviceId.get();
-}
-
-input_property_map_t* MockInputHost::getDevicePropertyMap(input_device_identifier_t* id) {
- mMapAllocations++;
- // Handled in the MockInputHost.
- return nullptr;
-}
-
-input_property_t* MockInputHost::getDeviceProperty(input_property_map_t* map, const char* key) {
- mPropertyAllocations[key]++;
- return new input_property_t{.key = String8(key)};
-}
-
-const char* MockInputHost::getPropertyKey(input_property_t* property) {
- return property->key.string();
-}
-
-const char* MockInputHost::getPropertyValue(input_property_t* property) {
- if (!mDevicePropertyMap.tryGetProperty(property->key, property->value)) {
- return nullptr;
- }
- return property->value.string();
-}
-
-void MockInputHost::freeDeviceProperty(input_property_t* property) {
- if (property != nullptr) {
- mPropertyAllocations[property->key.string()]--;
- delete property;
- }
-}
-
-void MockInputHost::freeDevicePropertyMap(input_property_map_t* map) {
- mMapAllocations--;
-}
-
-input_host_callbacks_t kTestCallbacks = {
- .create_device_identifier = create_device_identifier,
- .create_device_definition = create_device_definition,
- .create_input_report_definition = create_input_report_definition,
- .create_output_report_definition = create_output_report_definition,
- .input_device_definition_add_report = input_device_definition_add_report,
- .input_report_definition_add_collection = input_report_definition_add_collection,
- .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int,
- .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool,
- .register_device = register_device,
- .input_allocate_report = input_allocate_report,
- .input_report_set_usage_int = input_report_set_usage_int,
- .input_report_set_usage_bool = input_report_set_usage_bool,
- .report_event = report_event,
- .input_get_device_property_map = input_get_device_property_map,
- .input_get_device_property = input_get_device_property,
- .input_get_property_key = input_get_property_key,
- .input_get_property_value = input_get_property_value,
- .input_free_device_property = input_free_device_property,
- .input_free_device_property_map = input_free_device_property_map,
-};
-
bool MockInputDeviceNode::hasKeyInRange(int32_t startKey, int32_t endKey) const {
auto iter = mKeys.lower_bound(startKey);
if (iter == mKeys.end()) return false;
@@ -321,86 +224,4 @@
} // namespace MockNexusPlayer
-::input_device_identifier_t* create_device_identifier(input_host_t* host,
- const char* name, int32_t product_id, int32_t vendor_id,
- input_bus_t bus, const char* unique_id) {
- auto mockHost = static_cast<MockInputHost*>(host);
- return mockHost->createDeviceIdentifier(name, product_id, vendor_id, bus, unique_id);
-}
-
-input_device_definition_t* create_device_definition(input_host_t* host) {
- return nullptr;
-}
-
-input_report_definition_t* create_input_report_definition(input_host_t* host) {
- return nullptr;
-}
-
-input_report_definition_t* create_output_report_definition(input_host_t* host) {
- return nullptr;
-}
-
-void input_device_definition_add_report(input_host_t* host,
- input_device_definition_t* d, input_report_definition_t* r) { }
-
-void input_report_definition_add_collection(input_host_t* host,
- input_report_definition_t* report, input_collection_id_t id, int32_t arity) { }
-
-void input_report_definition_declare_usage_int(input_host_t* host,
- input_report_definition_t* report, input_collection_id_t id,
- input_usage_t usage, int32_t min, int32_t max, float resolution) { }
-
-void input_report_definition_declare_usages_bool(input_host_t* host,
- input_report_definition_t* report, input_collection_id_t id,
- input_usage_t* usage, size_t usage_count) { }
-
-
-input_device_handle_t* register_device(input_host_t* host,
- input_device_identifier_t* id, input_device_definition_t* d) {
- return nullptr;
-}
-
-input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) {
- return nullptr;
-}
-void input_report_set_usage_int(input_host_t* host, input_report_t* r,
- input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { }
-
-void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
- input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { }
-
-void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { }
-
-input_property_map_t* input_get_device_property_map(input_host_t* host,
- input_device_identifier_t* id) {
- auto mockHost = static_cast<MockInputHost*>(host);
- return mockHost->getDevicePropertyMap(id);
-}
-
-input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
- const char* key) {
- auto mockHost = static_cast<MockInputHost*>(host);
- return mockHost->getDeviceProperty(map, key);
-}
-
-const char* input_get_property_key(input_host_t* host, input_property_t* property) {
- auto mockHost = static_cast<MockInputHost*>(host);
- return mockHost->getPropertyKey(property);
-}
-
-const char* input_get_property_value(input_host_t* host, input_property_t* property) {
- auto mockHost = static_cast<MockInputHost*>(host);
- return mockHost->getPropertyValue(property);
-}
-
-void input_free_device_property(input_host_t* host, input_property_t* property) {
- auto mockHost = static_cast<MockInputHost*>(host);
- return mockHost->freeDeviceProperty(property);
-}
-
-void input_free_device_property_map(input_host_t* host, input_property_map_t* map) {
- auto mockHost = static_cast<MockInputHost*>(host);
- return mockHost->freeDevicePropertyMap(map);
-}
-
} // namespace android
diff --git a/tests/input/evdev/InputMocks.h b/tests/input/evdev/InputMocks.h
index 5c6eb80..78e0279 100644
--- a/tests/input/evdev/InputMocks.h
+++ b/tests/input/evdev/InputMocks.h
@@ -18,72 +18,15 @@
#define ANDROID_INPUT_MOCKS_H_
#include <map>
-#include <memory>
#include <set>
#include <string>
-#include <unordered_map>
#include <linux/input.h>
-#include <hardware/input.h>
-#include <utils/PropertyMap.h>
-
#include "InputHub.h"
-// Test definitions of opaque HAL structs
-struct input_host {};
-struct input_device_identifier {
- const char* name;
- const char* uniqueId;
- input_bus_t bus;
- int32_t vendorId;
- int32_t productId;
- int32_t version;
-};
-
-
namespace android {
-extern input_host_callbacks_t kTestCallbacks;
-
-class MockInputHost : public ::input_host_t {
-public:
- virtual ~MockInputHost() = default;
-
- void addDeviceProperty(const std::string& key, const std::string& value) {
- mDevicePropertyMap.addProperty(String8(key.c_str()), String8(value.c_str()));
- }
-
- /**
- * Call this at the end of a test to verify that any allocations made
- * during the test were freed.
- */
- bool checkAllocations() const;
-
- // Callbacks
- input_device_identifier_t* createDeviceIdentifier(
- const char* name, int32_t product_id, int32_t vendor_id,
- input_bus_t bus, const char* unique_id);
-
- input_property_map_t* getDevicePropertyMap(input_device_identifier_t* id);
-
- input_property_t* getDeviceProperty(input_property_map_t* map, const char* key);
-
- const char* getPropertyKey(input_property_t* property);
-
- const char* getPropertyValue(input_property_t* property);
-
- void freeDeviceProperty(input_property_t* property);
-
- void freeDevicePropertyMap(input_property_map_t* map);
-
-private:
- PropertyMap mDevicePropertyMap;
- std::unique_ptr<input_device_identifier_t> mDeviceId;
- int32_t mMapAllocations = 0;
- std::unordered_map<std::string, int32_t> mPropertyAllocations;
-};
-
class MockInputDeviceNode : public InputDeviceNode {
public:
MockInputDeviceNode() = default;
@@ -194,63 +137,6 @@
MockInputDeviceNode* getAsusGamepad();
} // namespace MockNexusPlayer
-// HAL method prototypes used in mock callbacks
-extern "C" {
-input_device_identifier_t* create_device_identifier(input_host_t* host,
- const char* name, int32_t product_id, int32_t vendor_id,
- input_bus_t bus, const char* unique_id);
-
-input_device_definition_t* create_device_definition(input_host_t* host);
-
-input_report_definition_t* create_input_report_definition(input_host_t* host);
-
-input_report_definition_t* create_output_report_definition(input_host_t* host);
-
-void input_device_definition_add_report(input_host_t* host,
- input_device_definition_t* d, input_report_definition_t* r);
-
-void input_report_definition_add_collection(input_host_t* host,
- input_report_definition_t* report, input_collection_id_t id, int32_t arity);
-
-void input_report_definition_declare_usage_int(input_host_t* host,
- input_report_definition_t* report, input_collection_id_t id,
- input_usage_t usage, int32_t min, int32_t max, float resolution);
-
-void input_report_definition_declare_usages_bool(input_host_t* host,
- input_report_definition_t* report, input_collection_id_t id,
- input_usage_t* usage, size_t usage_count);
-
-
-input_device_handle_t* register_device(input_host_t* host,
- input_device_identifier_t* id, input_device_definition_t* d);
-
-void unregister_device(input_host_t* host, input_device_handle_t* handle);
-
-input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r);
-
-void input_report_set_usage_int(input_host_t* host, input_report_t* r,
- input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index);
-
-void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
- input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index);
-
-void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report);
-
-input_property_map_t* input_get_device_property_map(input_host_t* host,
- input_device_identifier_t* id);
-
-input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
- const char* key);
-
-const char* input_get_property_key(input_host_t* host, input_property_t* property);
-
-const char* input_get_property_value(input_host_t* host, input_property_t* property);
-
-void input_free_device_property(input_host_t* host, input_property_t* property);
-
-void input_free_device_property_map(input_host_t* host, input_property_map_t* map);
-} // extern "C"
-
} // 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..a91f95c
--- /dev/null
+++ b/tests/input/evdev/MockInputHost.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_MOCK_INPUT_HOST_H_
+#define ANDROID_MOCK_INPUT_HOST_H_
+
+#include "gmock/gmock.h"
+
+#include "InputHost.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/SwitchInputMapper_test.cpp b/tests/input/evdev/SwitchInputMapper_test.cpp
new file mode 100644
index 0000000..f93041b
--- /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)));
+
+ 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);
+
+ 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
+