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
This commit is contained in:
parent
61809ac218
commit
4f3145d75f
19 changed files with 801 additions and 520 deletions
|
@ -375,13 +375,23 @@ typedef enum {
|
|||
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;
|
||||
|
||||
|
@ -412,6 +422,11 @@ typedef struct input_host_callbacks {
|
|||
input_report_definition_t* (*create_input_report_definition)(input_host_t* host);
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -21,7 +21,9 @@ LOCAL_SRC_FILES := \
|
|||
InputHub.cpp \
|
||||
InputDevice.cpp \
|
||||
InputDeviceManager.cpp \
|
||||
InputHost.cpp
|
||||
InputHost.cpp \
|
||||
InputMapper.cpp \
|
||||
SwitchInputMapper.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libhardware_legacy \
|
||||
|
|
|
@ -37,7 +37,8 @@ static const char kDevInput[] = "/dev/input";
|
|||
|
||||
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 @@ public:
|
|||
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 @@ private:
|
|||
|
||||
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 int dummy_open(const hw_module_t __unused *module, const char __unused *i
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -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 @@ static bool getBooleanProperty(const InputProperty& prop) {
|
|||
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 @@ static void setDeviceClasses(const InputDeviceNode* node, uint32_t* classes) {
|
|||
// 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 @@ static void setDeviceClasses(const InputDeviceNode* node, uint32_t* classes) {
|
|||
|
||||
// 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 @@ void EvdevDevice::processInput(InputEvent& event, nsecs_t currentTime) {
|
|||
", call time %" PRId64 ".", event.when, time, currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mMappers.size(); ++i) {
|
||||
mMappers[i]->process(event);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
|
|
@ -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 @@ protected:
|
|||
*/
|
||||
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;
|
||||
|
|
|
@ -43,7 +43,8 @@ void InputDeviceManager::onDeviceRemoved(const std::shared_ptr<InputDeviceNode>&
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace android {
|
|||
*/
|
||||
class InputDeviceManager : public InputCallbackInterface {
|
||||
public:
|
||||
explicit InputDeviceManager(InputHost host) :
|
||||
explicit InputDeviceManager(InputHostInterface* host) :
|
||||
mHost(host) {}
|
||||
virtual ~InputDeviceManager() override = default;
|
||||
|
||||
|
@ -45,7 +45,7 @@ public:
|
|||
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>>;
|
||||
|
|
|
@ -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 @@ void InputReportDefinition::declareUsage(InputCollectionId id, InputUsage usage,
|
|||
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 @@ const char* InputProperty::getValue() const {
|
|||
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
|
||||
|
|
|
@ -25,17 +25,17 @@ namespace android {
|
|||
|
||||
/**
|
||||
* 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 @@ protected:
|
|||
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 @@ protected:
|
|||
|
||||
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
|
||||
|
|
28
modules/input/evdev/InputMapper.cpp
Normal file
28
modules/input/evdev/InputMapper.cpp
Normal file
|
@ -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
|
82
modules/input/evdev/InputMapper.h
Normal file
82
modules/input/evdev/InputMapper.h
Normal file
|
@ -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_
|
123
modules/input/evdev/SwitchInputMapper.cpp
Normal file
123
modules/input/evdev/SwitchInputMapper.cpp
Normal file
|
@ -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
|
52
modules/input/evdev/SwitchInputMapper.h
Normal file
52
modules/input/evdev/SwitchInputMapper.h
Normal file
|
@ -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_
|
|
@ -2,13 +2,17 @@ LOCAL_PATH:= $(call my-dir)
|
|||
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 \
|
||||
|
|
|
@ -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, testOverrideTime) {
|
|||
}
|
||||
|
||||
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, testWrongClockCorrection) {
|
|||
}
|
||||
|
||||
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, testClockCorrectionOk) {
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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 @@ MockInputDeviceNode* getAsusGamepad() {
|
|||
|
||||
} // 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
|
||||
|
|
|
@ -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* getNexusRemote();
|
|||
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_
|
||||
|
|
88
tests/input/evdev/MockInputHost.h
Normal file
88
tests/input/evdev/MockInputHost.h
Normal file
|
@ -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_
|
106
tests/input/evdev/SwitchInputMapper_test.cpp
Normal file
106
tests/input/evdev/SwitchInputMapper_test.cpp
Normal file
|
@ -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
|
||||
|
Loading…
Reference in a new issue