1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "common.h" 18 #include "wear_touch.h" 19 20 #include <dirent.h> 21 #include <fcntl.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <errno.h> 26 #include <string.h> 27 28 #include <linux/input.h> 29 30 #define DEVICE_PATH "/dev/input" 31 32 WearSwipeDetector::WearSwipeDetector(int low, int high, OnSwipeCallback callback, void* cookie): 33 mLowThreshold(low), 34 mHighThreshold(high), 35 mCallback(callback), 36 mCookie(cookie), 37 mCurrentSlot(-1) { 38 pthread_create(&mThread, NULL, touch_thread, this); 39 } 40 41 WearSwipeDetector::~WearSwipeDetector() { 42 } 43 44 void WearSwipeDetector::detect(int dx, int dy) { 45 enum SwipeDirection direction; 46 47 if (abs(dy) < mLowThreshold && abs(dx) > mHighThreshold) { 48 direction = dx < 0 ? LEFT : RIGHT; 49 } else if (abs(dx) < mLowThreshold && abs(dy) > mHighThreshold) { 50 direction = dy < 0 ? UP : DOWN; 51 } else { 52 LOGD("Ignore %d %d\n", dx, dy); 53 return; 54 } 55 56 LOGD("Swipe direction=%d\n", direction); 57 mCallback(mCookie, direction); 58 } 59 60 void WearSwipeDetector::process(struct input_event *event) { 61 if (mCurrentSlot < 0) { 62 mCallback(mCookie, UP); 63 mCurrentSlot = 0; 64 } 65 66 if (event->type == EV_ABS) { 67 if (event->code == ABS_MT_SLOT) 68 mCurrentSlot = event->value; 69 70 // Ignore other fingers 71 if (mCurrentSlot > 0) { 72 return; 73 } 74 75 switch (event->code) { 76 case ABS_MT_POSITION_X: 77 mX = event->value; 78 mFingerDown = true; 79 break; 80 81 case ABS_MT_POSITION_Y: 82 mY = event->value; 83 mFingerDown = true; 84 break; 85 86 case ABS_MT_TRACKING_ID: 87 if (event->value < 0) 88 mFingerDown = false; 89 break; 90 } 91 } else if (event->type == EV_SYN) { 92 if (event->code == SYN_REPORT) { 93 if (mFingerDown && !mSwiping) { 94 mStartX = mX; 95 mStartY = mY; 96 mSwiping = true; 97 } else if (!mFingerDown && mSwiping) { 98 mSwiping = false; 99 detect(mX - mStartX, mY - mStartY); 100 } 101 } 102 } 103 } 104 105 void WearSwipeDetector::run() { 106 int fd = findDevice(DEVICE_PATH); 107 if (fd < 0) { 108 LOGE("no input devices found\n"); 109 return; 110 } 111 112 struct input_event event; 113 while (read(fd, &event, sizeof(event)) == sizeof(event)) { 114 process(&event); 115 } 116 117 close(fd); 118 } 119 120 void* WearSwipeDetector::touch_thread(void* cookie) { 121 ((WearSwipeDetector*)cookie)->run(); 122 return NULL; 123 } 124 125 #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) 126 127 int WearSwipeDetector::openDevice(const char *device) { 128 int fd = open(device, O_RDONLY); 129 if (fd < 0) { 130 LOGE("could not open %s, %s\n", device, strerror(errno)); 131 return false; 132 } 133 134 char name[80]; 135 name[sizeof(name) - 1] = '\0'; 136 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { 137 LOGE("could not get device name for %s, %s\n", device, strerror(errno)); 138 name[0] = '\0'; 139 } 140 141 uint8_t bits[512]; 142 memset(bits, 0, sizeof(bits)); 143 int ret = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); 144 if (ret > 0) { 145 if (test_bit(ABS_MT_POSITION_X, bits) && test_bit(ABS_MT_POSITION_Y, bits)) { 146 LOGD("Found %s %s\n", device, name); 147 return fd; 148 } 149 } 150 151 close(fd); 152 return -1; 153 } 154 155 int WearSwipeDetector::findDevice(const char* path) { 156 DIR* dir = opendir(path); 157 if (dir == NULL) { 158 LOGE("Could not open directory %s", path); 159 return false; 160 } 161 162 struct dirent* entry; 163 int ret = -1; 164 while (ret < 0 && (entry = readdir(dir)) != NULL) { 165 if (entry->d_name[0] == '.') continue; 166 167 char device[PATH_MAX]; 168 device[PATH_MAX-1] = '\0'; 169 snprintf(device, PATH_MAX-1, "%s/%s", path, entry->d_name); 170 171 ret = openDevice(device); 172 } 173 174 closedir(dir); 175 return ret; 176 } 177 178