diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml
index d966b97..33c83b7 100644
--- a/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/overlay/frameworks/base/core/res/res/values/config.xml
@@ -29,6 +29,9 @@
that can be set by the user. -->
17
+
+ org.lineageos.sensor.single_touch
+
true
diff --git a/sensors/Sensor.cpp b/sensors/Sensor.cpp
index 6e75b5f..b1991ee 100644
--- a/sensors/Sensor.cpp
+++ b/sensors/Sensor.cpp
@@ -24,6 +24,25 @@
namespace {
+static bool readBool(int fd) {
+ char c;
+ int rc;
+
+ rc = lseek(fd, 0, SEEK_SET);
+ if (rc) {
+ ALOGE("failed to seek fd, err: %d", rc);
+ return false;
+ }
+
+ rc = read(fd, &c, sizeof(char));
+ if (rc != 1) {
+ ALOGE("failed to read bool from fd, err: %d", rc);
+ return false;
+ }
+
+ return c != '0';
+}
+
static bool readFpState(int fd, int& screenX, int& screenY) {
char buffer[512];
int state = 0;
@@ -333,6 +352,115 @@ void UdfpsSensor::interruptPoll() {
write(mWaitPipeFd[1], &c, sizeof(c));
}
+SingleTapSensor::SingleTapSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OneShotSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Single Tap Sensor";
+ mSensorInfo.type =
+ static_cast(static_cast(SensorType::DEVICE_PRIVATE_BASE) + 2);
+ mSensorInfo.typeAsString = "org.lineageos.sensor.single_touch";
+ mSensorInfo.maxRange = 2048.0f;
+ mSensorInfo.resolution = 1.0f;
+ mSensorInfo.power = 0;
+ mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
+
+ int rc;
+
+ rc = pipe(mWaitPipeFd);
+ if (rc < 0) {
+ mWaitPipeFd[0] = -1;
+ mWaitPipeFd[1] = -1;
+ ALOGE("failed to open wait pipe: %d", rc);
+ }
+
+ mPollFd = open("/sys/class/spi_master/spi0/spi0.0/fts_gesture_single_tap_pressed", O_RDONLY);
+ if (mPollFd < 0) {
+ ALOGE("failed to open poll fd: %d", mPollFd);
+ }
+
+ if (mWaitPipeFd[0] < 0 || mWaitPipeFd[1] < 0 || mPollFd < 0) {
+ mStopThread = true;
+ return;
+ }
+
+ mPolls[0] = {
+ .fd = mWaitPipeFd[0],
+ .events = POLLIN,
+ };
+
+ mPolls[1] = {
+ .fd = mPollFd,
+ .events = POLLERR | POLLPRI,
+ };
+}
+
+SingleTapSensor::~SingleTapSensor() {
+ interruptPoll();
+}
+
+void SingleTapSensor::activate(bool enable) {
+ std::lock_guard lock(mRunMutex);
+
+ if (mIsEnabled != enable) {
+ mIsEnabled = enable;
+
+ interruptPoll();
+ mWaitCV.notify_all();
+ }
+}
+
+void SingleTapSensor::setOperationMode(OperationMode mode) {
+ Sensor::setOperationMode(mode);
+ interruptPoll();
+}
+
+void SingleTapSensor::run() {
+ std::unique_lock runLock(mRunMutex);
+
+ while (!mStopThread) {
+ if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+ mWaitCV.wait(runLock, [&] {
+ return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+ });
+ } else {
+ // Cannot hold lock while polling.
+ runLock.unlock();
+ int rc = poll(mPolls, 2, -1);
+ runLock.lock();
+
+ if (rc < 0) {
+ ALOGE("failed to poll: %d", rc);
+ mStopThread = true;
+ continue;
+ }
+
+ if (mPolls[1].revents == mPolls[1].events && readBool(mPollFd)) {
+ mIsEnabled = false;
+ mCallback->postEvents(readEvents(), isWakeUpSensor());
+ } else if (mPolls[0].revents == mPolls[0].events) {
+ char buf;
+ read(mWaitPipeFd[0], &buf, sizeof(buf));
+ }
+ }
+ }
+}
+
+std::vector SingleTapSensor::readEvents() {
+ std::vector events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ events.push_back(event);
+ return events;
+}
+
+void SingleTapSensor::interruptPoll() {
+ if (mWaitPipeFd[1] < 0) return;
+
+ char c = '1';
+ write(mWaitPipeFd[1], &c, sizeof(c));
+}
+
} // namespace implementation
} // namespace subhal
} // namespace V2_1
diff --git a/sensors/Sensor.h b/sensors/Sensor.h
index aa1f194..7586f21 100644
--- a/sensors/Sensor.h
+++ b/sensors/Sensor.h
@@ -114,6 +114,26 @@ class UdfpsSensor : public OneShotSensor {
int mScreenY;
};
+class SingleTapSensor : public OneShotSensor {
+ public:
+ SingleTapSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+ virtual ~SingleTapSensor() override;
+
+ virtual void activate(bool enable) override;
+ virtual void setOperationMode(OperationMode mode) override;
+
+ protected:
+ virtual void run() override;
+ virtual std::vector readEvents();
+
+ private:
+ void interruptPoll();
+
+ struct pollfd mPolls[2];
+ int mWaitPipeFd[2];
+ int mPollFd;
+};
+
} // namespace implementation
} // namespace subhal
} // namespace V2_1
diff --git a/sensors/SensorsSubHal.cpp b/sensors/SensorsSubHal.cpp
index 9306b98..2e986f5 100644
--- a/sensors/SensorsSubHal.cpp
+++ b/sensors/SensorsSubHal.cpp
@@ -34,6 +34,7 @@ using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {
AddSensor();
+ AddSensor();
}
Return SensorsSubHal::getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) {