Support combined vibration effects with input device.
Support combined vibration effects with multi-channel FF effect input
device.
Bug: 161629089
Test: atest InputDeviceVibratorTest
Change-Id: I566f6cdd601f716b34c2f70e3705340ef8906897
diff --git a/services/inputflinger/VibrationElement.cpp b/services/inputflinger/VibrationElement.cpp
index aaf5834..17e1ad4 100644
--- a/services/inputflinger/VibrationElement.cpp
+++ b/services/inputflinger/VibrationElement.cpp
@@ -24,13 +24,28 @@
using android::base::StringPrintf;
namespace android {
+// VibrationElement implementations
+VibrationElement::VibrationElement(size_t channelNum) {
+ channels.reserve(channelNum);
+}
+
+VibrationElement::VibrationElement(const VibrationElement& other) {
+ duration = other.duration;
+ channels.resize(other.channels.size());
+ for (size_t i = 0; i < other.channels.size(); i++) {
+ channels[i].first = other.channels[i].first;
+ channels[i].second = other.channels[i].second;
+ }
+}
const std::string VibrationElement::toString() const {
std::string dump;
dump += StringPrintf("[duration=%lldms, channels=[", duration.count());
for (auto it = channels.begin(); it != channels.end(); ++it) {
- dump += std::to_string(*it);
+ dump += std::to_string(it->first);
+ dump += " : ";
+ dump += std::to_string(it->second);
if (std::next(it) != channels.end()) {
dump += ", ";
}
@@ -40,17 +55,79 @@
return dump;
}
-uint16_t VibrationElement::getMagnitude(size_t channelIdx) const {
- if (channelIdx >= channels.size()) {
+uint16_t VibrationElement::getMagnitude(int32_t vibratorId) const {
+ auto it =
+ std::find_if(channels.begin(), channels.end(),
+ [vibratorId](const std::pair<int32_t /*vibratorId*/, uint8_t /*amplitude*/>
+ pair) { return pair.first == vibratorId; });
+ if (it == channels.end()) {
return 0;
}
// convert range [0,255] to [0,65535] (android framework to linux ff ranges)
- return static_cast<uint16_t>(channels[channelIdx]) << 8;
+ return static_cast<uint16_t>(it->second) << 8;
}
bool VibrationElement::isOn() const {
return std::any_of(channels.begin(), channels.end(),
- [](uint16_t channel) { return channel != 0; });
+ [](const auto& channel) { return channel.second != 0; });
+}
+
+void VibrationElement::addChannel(int32_t vibratorId, uint8_t amplitude) {
+ channels.push_back(std::make_pair(vibratorId, amplitude));
+}
+
+bool VibrationElement::operator==(const VibrationElement& other) const {
+ if (duration != other.duration || channels.size() != other.channels.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < CHANNEL_SIZE; i++) {
+ if (channels[i] != other.channels[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VibrationElement::operator!=(const VibrationElement& other) const {
+ return !(*this == other);
+}
+
+// VibrationSequence implementations
+VibrationSequence::VibrationSequence(size_t length) {
+ pattern.reserve(length);
+}
+
+void VibrationSequence::operator=(const VibrationSequence& other) {
+ pattern = other.pattern;
+}
+
+bool VibrationSequence::operator==(const VibrationSequence& other) const {
+ if (pattern.size() != other.pattern.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < pattern.size(); i++) {
+ if (pattern[i] != other.pattern[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void VibrationSequence::addElement(VibrationElement element) {
+ pattern.push_back(element);
+}
+
+const std::string VibrationSequence::toString() const {
+ std::string dump;
+ dump += "[";
+
+ for (const auto& element : pattern) {
+ dump += element.toString();
+ dump += " ";
+ }
+
+ dump += "]";
+ return dump;
}
} // namespace android
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index ffd8bf2..6cce8ec 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -101,10 +101,14 @@
virtual void requestRefreshConfiguration(uint32_t changes) = 0;
/* Controls the vibrator of a particular input device. */
- virtual void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
- ssize_t repeat, int32_t token) = 0;
+ virtual void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
+ int32_t token) = 0;
virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
+ virtual bool isVibrating(int32_t deviceId) = 0;
+
+ virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
+
/* Return true if the device can send input events to the specified display. */
virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
};
diff --git a/services/inputflinger/include/VibrationElement.h b/services/inputflinger/include/VibrationElement.h
index b60ffac..736041e 100644
--- a/services/inputflinger/include/VibrationElement.h
+++ b/services/inputflinger/include/VibrationElement.h
@@ -21,6 +21,7 @@
#include <chrono>
#include <cstdint>
#include <string>
+#include <vector>
namespace android {
@@ -32,13 +33,43 @@
struct VibrationElement {
std::chrono::milliseconds duration;
// Channel amplitude range 0-255.
- std::array<uint8_t, CHANNEL_SIZE> channels = {0, 0};
+ std::vector<std::pair<int32_t /*vibratorId*/, uint8_t /*amplitude*/>> channels;
+
+ explicit VibrationElement(size_t channelNum);
+
+ VibrationElement(const VibrationElement& other);
+
+ bool operator==(const VibrationElement& other) const;
+
+ bool operator!=(const VibrationElement& other) const;
+
+ void addChannel(int32_t vibratorId, uint8_t amplitude);
const std::string toString() const;
- uint16_t getMagnitude(size_t channelIndex) const;
+
+ uint16_t getMagnitude(int32_t vibratorId) const;
+
bool isOn() const;
};
+/*
+ * Describes a sequence of rumble effect
+ */
+struct VibrationSequence {
+ // Pattern of vibration elements
+ std::vector<VibrationElement> pattern;
+
+ explicit VibrationSequence(size_t length);
+
+ void operator=(const VibrationSequence& other);
+
+ bool operator==(const VibrationSequence& other) const;
+
+ void addElement(VibrationElement element);
+
+ const std::string toString() const;
+};
+
} // namespace android
#endif // _VIBRATION_ELEMENT_H
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 9671dec..f864c0e 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -61,8 +61,8 @@
// v4l2 devices go directly into /dev
static const char* VIDEO_DEVICE_PATH = "/dev";
-static constexpr size_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
-static constexpr size_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
+static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
+static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
static inline const char* toString(bool value) {
return value ? "true" : "false";
@@ -475,25 +475,25 @@
}
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->identifier : InputDeviceIdentifier();
}
Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->classes : Flags<InputDeviceClass>(0);
}
int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->controllerNumber : 0;
}
void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->configuration) {
*outConfiguration = *device->configuration;
@@ -507,7 +507,7 @@
outAxisInfo->clear();
if (axis >= 0 && axis <= ABS_MAX) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
@@ -534,7 +534,7 @@
bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
if (axis >= 0 && axis <= REL_MAX) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->relBitmask.test(axis) : false;
}
@@ -542,7 +542,7 @@
}
bool EventHub::hasInputProperty(int32_t deviceId, int property) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
return property >= 0 && property <= INPUT_PROP_MAX && device != nullptr
@@ -552,7 +552,7 @@
int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
if (scanCode >= 0 && scanCode <= KEY_MAX) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) {
@@ -565,7 +565,7 @@
}
int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
@@ -588,7 +588,7 @@
int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
if (sw >= 0 && sw <= SW_MAX) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) {
@@ -604,7 +604,7 @@
*outValue = 0;
if (axis >= 0 && axis <= ABS_MAX) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
@@ -624,7 +624,7 @@
bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->keyMap.haveKeyLayout()) {
@@ -652,7 +652,7 @@
status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
@@ -692,7 +692,7 @@
}
status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->keyMap.haveKeyLayout()) {
@@ -706,13 +706,13 @@
}
void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
mExcludedDevices = devices;
}
bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && scanCode >= 0 && scanCode <= KEY_MAX) {
return device->keyBitmask.test(scanCode);
@@ -721,7 +721,7 @@
}
bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
int32_t sc;
if (device != nullptr && device->mapLed(led, &sc) == NO_ERROR) {
@@ -731,7 +731,7 @@
}
void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd()) {
device->setLedStateLocked(led, on);
@@ -742,7 +742,7 @@
std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
outVirtualKeys.clear();
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->virtualKeyMap) {
const std::vector<VirtualKeyDefinition> virtualKeys =
@@ -752,7 +752,7 @@
}
const std::shared_ptr<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr) {
return device->getKeyCharacterMap();
@@ -761,7 +761,7 @@
}
bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) {
device->keyMap.keyCharacterMap->combine(*map);
@@ -822,7 +822,7 @@
}
void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd()) {
ff_effect effect;
@@ -857,7 +857,7 @@
}
void EventHub::cancelVibrate(int32_t deviceId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd()) {
if (device->ffEffectPlaying) {
@@ -878,6 +878,18 @@
}
}
+std::vector<int32_t> EventHub::getVibratorIds(int32_t deviceId) {
+ std::scoped_lock _l(mLock);
+ std::vector<int32_t> vibrators;
+ Device* device = getDeviceLocked(deviceId);
+ if (device != nullptr && device->hasValidFd() &&
+ device->classes.test(InputDeviceClass::VIBRATOR)) {
+ vibrators.push_back(FF_STRONG_MAGNITUDE_CHANNEL_IDX);
+ vibrators.push_back(FF_WEAK_MAGNITUDE_CHANNEL_IDX);
+ }
+ return vibrators;
+}
+
EventHub::Device* EventHub::getDeviceByDescriptorLocked(const std::string& descriptor) const {
for (const auto& [id, device] : mDevices) {
if (descriptor == device->identifier.descriptor) {
@@ -930,7 +942,7 @@
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
struct input_event readBuffer[bufferSize];
@@ -1184,7 +1196,7 @@
}
std::vector<TouchVideoFrame> EventHub::getVideoFrames(int32_t deviceId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr || !device->videoDevice) {
@@ -1593,7 +1605,7 @@
}
bool EventHub::isDeviceEnabled(int32_t deviceId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1603,7 +1615,7 @@
}
status_t EventHub::enableDevice(int32_t deviceId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1625,7 +1637,7 @@
}
status_t EventHub::disableDevice(int32_t deviceId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1809,7 +1821,7 @@
void EventHub::requestReopenDevices() {
ALOGV("requestReopenDevices() called");
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
mNeedToReopenDevices = true;
}
@@ -1817,7 +1829,7 @@
dump += "Event Hub State:\n";
{ // acquire lock
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
dump += StringPrintf(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 271bc2f..d25d64a 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -429,10 +429,9 @@
return result;
}
-void InputDevice::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
- int32_t token) {
- for_each_mapper([pattern, repeat, token](InputMapper& mapper) {
- mapper.vibrate(pattern, repeat, token);
+void InputDevice::vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) {
+ for_each_mapper([sequence, repeat, token](InputMapper& mapper) {
+ mapper.vibrate(sequence, repeat, token);
});
}
@@ -440,6 +439,27 @@
for_each_mapper([token](InputMapper& mapper) { mapper.cancelVibrate(token); });
}
+bool InputDevice::isVibrating() {
+ bool vibrating = false;
+ for_each_mapper([&vibrating](InputMapper& mapper) { vibrating |= mapper.isVibrating(); });
+ return vibrating;
+}
+
+/* There's no guarantee the IDs provided by the different mappers are unique, so if we have two
+ * different vibration mappers then we could have duplicate IDs.
+ * Alternatively, if we have a merged device that has multiple evdev nodes with FF_* capabilities,
+ * we would definitely have duplicate IDs.
+ */
+std::vector<int32_t> InputDevice::getVibratorIds() {
+ std::vector<int32_t> vibrators;
+ for_each_mapper([&vibrators](InputMapper& mapper) {
+ std::vector<int32_t> devVibs = mapper.getVibratorIds();
+ vibrators.reserve(vibrators.size() + devVibs.size());
+ vibrators.insert(vibrators.end(), devVibs.begin(), devVibs.end());
+ });
+ return vibrators;
+}
+
void InputDevice::cancelTouch(nsecs_t when) {
for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); });
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 6216d78..a6b5e2d 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -56,7 +56,7 @@
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
@@ -89,7 +89,7 @@
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
{ // acquire lock
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
@@ -108,7 +108,7 @@
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
mReaderIsAliveCondition.notify_all();
if (count) {
@@ -407,7 +407,7 @@
}
void InputReader::dispatchExternalStylusState(const StylusState& state) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
for (auto& devicePair : mDevices) {
std::shared_ptr<InputDevice>& device = devicePair.second;
device->updateExternalStylusState(state);
@@ -482,7 +482,7 @@
}
std::vector<InputDeviceInfo> InputReader::getInputDevices() const {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
return getInputDevicesLocked();
}
@@ -501,19 +501,19 @@
}
int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState);
}
int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState);
}
int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState);
}
@@ -545,7 +545,7 @@
}
void InputReader::toggleCapsLockState(int32_t deviceId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
InputDevice* device = findInputDeviceLocked(deviceId);
if (!device) {
ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId);
@@ -561,7 +561,7 @@
bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
memset(outFlags, 0, numCodes);
return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags);
@@ -588,7 +588,7 @@
}
void InputReader::requestRefreshConfiguration(uint32_t changes) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
if (changes) {
bool needWake = !mConfigurationChangesToRefresh;
@@ -600,17 +600,18 @@
}
}
-void InputReader::vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
- ssize_t repeat, int32_t token) {
- std::lock_guard<std::mutex> lock(mLock);
+void InputReader::vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
+ int32_t token) {
+ std::scoped_lock _l(mLock);
+
InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
- device->vibrate(pattern, repeat, token);
+ device->vibrate(sequence, repeat, token);
}
}
void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
@@ -618,8 +619,28 @@
}
}
+bool InputReader::isVibrating(int32_t deviceId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->isVibrating();
+ }
+ return false;
+}
+
+std::vector<int32_t> InputReader::getVibratorIds(int32_t deviceId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->getVibratorIds();
+ }
+ return {};
+}
+
bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
@@ -630,7 +651,7 @@
}
bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
InputDevice* device = findInputDeviceLocked(deviceId);
if (!device) {
@@ -658,7 +679,7 @@
}
void InputReader::dump(std::string& dump) {
- std::lock_guard<std::mutex> lock(mLock);
+ std::scoped_lock _l(mLock);
mEventHub->dump(dump);
dump += "\n";
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index a3f881e..9e38d0a 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -233,6 +233,7 @@
/* Control the vibrator. */
virtual void vibrate(int32_t deviceId, const VibrationElement& effect) = 0;
virtual void cancelVibrate(int32_t deviceId) = 0;
+ virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
/* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
virtual void requestReopenDevices() = 0;
@@ -381,6 +382,7 @@
void vibrate(int32_t deviceId, const VibrationElement& effect) override final;
void cancelVibrate(int32_t deviceId) override final;
+ std::vector<int32_t> getVibratorIds(int32_t deviceId) override final;
void requestReopenDevices() override final;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 7d160eb..8b14b06 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -82,8 +82,10 @@
int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags);
- void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat, int32_t token);
+ void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
void cancelVibrate(int32_t token);
+ bool isVibrating();
+ std::vector<int32_t> getVibratorIds();
void cancelTouch(nsecs_t when);
int32_t getMetaState();
@@ -272,6 +274,8 @@
}
inline void cancelVibrate() { return mEventHub->cancelVibrate(mId); }
+ inline std::vector<int32_t> getVibratorIds() { return mEventHub->getVibratorIds(mId); }
+
inline bool hasAbsoluteAxis(int32_t code) const {
RawAbsoluteAxisInfo info;
mEventHub->getAbsoluteAxisInfo(mId, code, &info);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 9b07681d..b16b86c 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -77,10 +77,14 @@
void requestRefreshConfiguration(uint32_t changes) override;
- void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern, ssize_t repeat,
+ void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
int32_t token) override;
void cancelVibrate(int32_t deviceId, int32_t token) override;
+ bool isVibrating(int32_t deviceId) override;
+
+ std::vector<int32_t> getVibratorIds(int32_t deviceId) override;
+
bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) override;
protected:
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index 1db829f..913cef7 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -56,11 +56,18 @@
return false;
}
-void InputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
- int32_t token) {}
+void InputMapper::vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) {}
void InputMapper::cancelVibrate(int32_t token) {}
+bool InputMapper::isVibrating() {
+ return false;
+}
+
+std::vector<int32_t> InputMapper::getVibratorIds() {
+ return {};
+}
+
void InputMapper::cancelTouch(nsecs_t when) {}
int32_t InputMapper::getMetaState() {
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 56ab928..088dbd8 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -63,9 +63,10 @@
virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags);
- virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
- int32_t token);
+ virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
virtual void cancelVibrate(int32_t token);
+ virtual bool isVibrating();
+ virtual std::vector<int32_t> getVibratorIds();
virtual void cancelTouch(nsecs_t when);
virtual int32_t getMetaState();
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index ac7c266..f25e59a 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -21,7 +21,7 @@
namespace android {
VibratorInputMapper::VibratorInputMapper(InputDeviceContext& deviceContext)
- : InputMapper(deviceContext), mVibrating(false) {}
+ : InputMapper(deviceContext), mVibrating(false), mSequence(0) {}
VibratorInputMapper::~VibratorInputMapper() {}
@@ -39,17 +39,15 @@
// TODO: Handle FF_STATUS, although it does not seem to be widely supported.
}
-void VibratorInputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
+void VibratorInputMapper::vibrate(const VibrationSequence& sequence, ssize_t repeat,
int32_t token) {
#if DEBUG_VIBRATOR
- std::string patternStr;
- dumpPattern(patternStr);
ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(),
- patternStr.c_str(), repeat, token);
+ sequence.toString().c_str(), repeat, token);
#endif
mVibrating = true;
- mPattern = pattern;
+ mSequence = sequence;
mRepeat = repeat;
mToken = token;
mIndex = -1;
@@ -67,6 +65,14 @@
}
}
+bool VibratorInputMapper::isVibrating() {
+ return mVibrating;
+}
+
+std::vector<int32_t> VibratorInputMapper::getVibratorIds() {
+ return getDeviceContext().getVibratorIds();
+}
+
void VibratorInputMapper::timeoutExpired(nsecs_t when) {
if (mVibrating) {
if (when >= mNextStepTime) {
@@ -79,7 +85,7 @@
void VibratorInputMapper::nextStep() {
mIndex += 1;
- if (size_t(mIndex) >= mPattern.size()) {
+ if (size_t(mIndex) >= mSequence.pattern.size()) {
if (mRepeat < 0) {
// We are done.
stopVibrating();
@@ -88,7 +94,7 @@
mIndex = mRepeat;
}
- const VibrationElement& element = mPattern[mIndex];
+ const VibrationElement& element = mSequence.pattern[mIndex];
if (element.isOn()) {
#if DEBUG_VIBRATOR
std::string description = element.toString();
@@ -125,23 +131,10 @@
dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating));
if (mVibrating) {
dump += INDENT3 "Pattern: ";
- dumpPattern(dump);
+ dump += mSequence.toString();
dump += "\n";
dump += StringPrintf(INDENT3 "Repeat Index: %zd\n", mRepeat);
}
}
-void VibratorInputMapper::dumpPattern(std::string& dump) const {
- dump += "[";
-
- for (auto it = mPattern.begin(); it != mPattern.end(); ++it) {
- dump += it->toString();
- if (std::next(it) != mPattern.end()) {
- dump += ", ";
- }
- }
-
- dump += "]";
-}
-
} // namespace android
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index bfa5ec1..7ce621a 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -30,21 +30,21 @@
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
virtual void process(const RawEvent* rawEvent) override;
- virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
- int32_t token) override;
+ virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) override;
virtual void cancelVibrate(int32_t token) override;
+ virtual bool isVibrating() override;
+ virtual std::vector<int32_t> getVibratorIds() override;
virtual void timeoutExpired(nsecs_t when) override;
virtual void dump(std::string& dump) override;
private:
bool mVibrating;
- std::vector<VibrationElement> mPattern;
+ VibrationSequence mSequence;
ssize_t mRepeat;
int32_t mToken;
ssize_t mIndex;
nsecs_t mNextStepTime;
- void dumpPattern(std::string& dump) const;
void nextStep();
void stopVibrating();
};
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 5a4c881..cd61750 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -27,6 +27,7 @@
#include <TestInputListener.h>
#include <TouchInputMapper.h>
#include <UinputDevice.h>
+#include <VibratorInputMapper.h>
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
#include <inttypes.h>
@@ -396,6 +397,7 @@
std::vector<std::string> mExcludedDevices;
List<RawEvent> mEvents GUARDED_BY(mLock);
std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
+ std::vector<int32_t> mVibrators = {0, 1};
public:
virtual ~FakeEventHub() {
@@ -810,6 +812,8 @@
void cancelVibrate(int32_t) override {}
+ std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; };
+
virtual bool isExternal(int32_t) const {
return false;
}
@@ -1816,6 +1820,31 @@
ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
}
+class FakeVibratorInputMapper : public FakeInputMapper {
+public:
+ FakeVibratorInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
+ : FakeInputMapper(deviceContext, sources) {}
+
+ std::vector<int32_t> getVibratorIds() override { return getDeviceContext().getVibratorIds(); }
+};
+
+TEST_F(InputReaderTest, VibratorGetVibratorIds) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR;
+ constexpr int32_t eventHubId = 1;
+ const char* DEVICE_LOCATION = "BLUETOOTH";
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+ FakeVibratorInputMapper& mapper =
+ device->addMapper<FakeVibratorInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
+ mReader->pushNextDevice(device);
+
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+ ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
+
+ ASSERT_EQ(mapper.getVibratorIds().size(), 2U);
+ ASSERT_EQ(mReader->getVibratorIds(deviceId).size(), 2U);
+}
+
// --- InputReaderIntegrationTest ---
// These tests create and interact with the InputReader only through its interface.
@@ -2496,6 +2525,46 @@
ASSERT_EQ(uint32_t(0), args.policyFlags);
}
+// --- VibratorInputMapperTest ---
+class VibratorInputMapperTest : public InputMapperTest {
+protected:
+ void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::VIBRATOR); }
+};
+
+TEST_F(VibratorInputMapperTest, GetSources) {
+ VibratorInputMapper& mapper = addMapperAndConfigure<VibratorInputMapper>();
+
+ ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources());
+}
+
+TEST_F(VibratorInputMapperTest, GetVibratorIds) {
+ VibratorInputMapper& mapper = addMapperAndConfigure<VibratorInputMapper>();
+
+ ASSERT_EQ(mapper.getVibratorIds().size(), 2U);
+}
+
+TEST_F(VibratorInputMapperTest, Vibrate) {
+ constexpr uint8_t DEFAULT_AMPLITUDE = 192;
+ VibratorInputMapper& mapper = addMapperAndConfigure<VibratorInputMapper>();
+
+ VibrationElement pattern(2);
+ VibrationSequence sequence(2);
+ pattern.duration = std::chrono::milliseconds(200);
+ pattern.channels = {{0 /* vibratorId */, DEFAULT_AMPLITUDE / 2},
+ {1 /* vibratorId */, DEFAULT_AMPLITUDE}};
+ sequence.addElement(pattern);
+ pattern.duration = std::chrono::milliseconds(500);
+ pattern.channels = {{0 /* vibratorId */, DEFAULT_AMPLITUDE / 4},
+ {1 /* vibratorId */, DEFAULT_AMPLITUDE}};
+ sequence.addElement(pattern);
+
+ std::vector<int64_t> timings = {0, 1};
+ std::vector<uint8_t> amplitudes = {DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE / 2};
+
+ ASSERT_FALSE(mapper.isVibrating());
+ mapper.vibrate(sequence, -1 /* repeat */, 0 /* token */);
+ ASSERT_TRUE(mapper.isVibrating());
+}
// --- KeyboardInputMapperTest ---