/* * Copyright (C) 2016 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 "common.h" #include "wear_touch.h" #include #include #include #include #include #include #include #include #define DEVICE_PATH "/dev/input" WearSwipeDetector::WearSwipeDetector(int low, int high, OnSwipeCallback callback, void* cookie): mLowThreshold(low), mHighThreshold(high), mCallback(callback), mCookie(cookie), mCurrentSlot(-1) { pthread_create(&mThread, NULL, touch_thread, this); } WearSwipeDetector::~WearSwipeDetector() { } void WearSwipeDetector::detect(int dx, int dy) { enum SwipeDirection direction; if (abs(dy) < mLowThreshold && abs(dx) > mHighThreshold) { direction = dx < 0 ? LEFT : RIGHT; } else if (abs(dx) < mLowThreshold && abs(dy) > mHighThreshold) { direction = dy < 0 ? UP : DOWN; } else { LOGD("Ignore %d %d\n", dx, dy); return; } LOGD("Swipe direction=%d\n", direction); mCallback(mCookie, direction); } void WearSwipeDetector::process(struct input_event *event) { if (mCurrentSlot < 0) { mCallback(mCookie, UP); mCurrentSlot = 0; } if (event->type == EV_ABS) { if (event->code == ABS_MT_SLOT) mCurrentSlot = event->value; // Ignore other fingers if (mCurrentSlot > 0) { return; } switch (event->code) { case ABS_MT_POSITION_X: mX = event->value; mFingerDown = true; break; case ABS_MT_POSITION_Y: mY = event->value; mFingerDown = true; break; case ABS_MT_TRACKING_ID: if (event->value < 0) mFingerDown = false; break; } } else if (event->type == EV_SYN) { if (event->code == SYN_REPORT) { if (mFingerDown && !mSwiping) { mStartX = mX; mStartY = mY; mSwiping = true; } else if (!mFingerDown && mSwiping) { mSwiping = false; detect(mX - mStartX, mY - mStartY); } } } } void WearSwipeDetector::run() { int fd = findDevice(DEVICE_PATH); if (fd < 0) { LOGE("no input devices found\n"); return; } struct input_event event; while (read(fd, &event, sizeof(event)) == sizeof(event)) { process(&event); } close(fd); } void* WearSwipeDetector::touch_thread(void* cookie) { ((WearSwipeDetector*)cookie)->run(); return NULL; } #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) int WearSwipeDetector::openDevice(const char *device) { int fd = open(device, O_RDONLY); if (fd < 0) { LOGE("could not open %s, %s\n", device, strerror(errno)); return false; } char name[80]; name[sizeof(name) - 1] = '\0'; if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { LOGE("could not get device name for %s, %s\n", device, strerror(errno)); name[0] = '\0'; } uint8_t bits[512]; memset(bits, 0, sizeof(bits)); int ret = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); if (ret > 0) { if (test_bit(ABS_MT_POSITION_X, bits) && test_bit(ABS_MT_POSITION_Y, bits)) { LOGD("Found %s %s\n", device, name); return fd; } } close(fd); return -1; } int WearSwipeDetector::findDevice(const char* path) { DIR* dir = opendir(path); if (dir == NULL) { LOGE("Could not open directory %s", path); return false; } struct dirent* entry; int ret = -1; while (ret < 0 && (entry = readdir(dir)) != NULL) { if (entry->d_name[0] == '.') continue; char device[PATH_MAX]; device[PATH_MAX-1] = '\0'; snprintf(device, PATH_MAX-1, "%s/%s", path, entry->d_name); ret = openDevice(device); } closedir(dir); return ret; }