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 
WearSwipeDetector(int low,int high,OnSwipeCallback callback,void * cookie)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 
~WearSwipeDetector()41 WearSwipeDetector::~WearSwipeDetector() {
42 }
43 
detect(int dx,int dy)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 
process(struct input_event * event)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 
run()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 
touch_thread(void * cookie)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 
openDevice(const char * device)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 
findDevice(const char * path)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