hardware/libhardware_legacy
Revision | 36c6e87c8308ac979de7d861bf2f64d26aa1b198 (tree) |
---|---|
Time | 2011-07-12 16:06:24 |
Author | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
add powerbtnd to simulate long press of power button.
On x86 PC, power button usually generates key press and release events
simultaneously. However, the android framework expects a long press
of power button to invoke the power off dialog.
The daemon simulates a long press of power button in 2 seconds.
A target needs to add excluded-input-devices.xml to exclude
'Power Button' from processing by EventHub.
@@ -40,3 +40,14 @@ LOCAL_MODULE:= libpower | ||
40 | 40 | LOCAL_SRC_FILES += power/power.c |
41 | 41 | |
42 | 42 | include $(BUILD_STATIC_LIBRARY) |
43 | + | |
44 | +# powerbtn executable | |
45 | +include $(CLEAR_VARS) | |
46 | + | |
47 | +LOCAL_SRC_FILES := power/powerbtnd.c | |
48 | + | |
49 | +LOCAL_MODULE := powerbtnd | |
50 | +LOCAL_MODULE_TAGS := optional | |
51 | +LOCAL_SHARED_LIBRARIES := liblog | |
52 | + | |
53 | +include $(BUILD_EXECUTABLE) |
@@ -0,0 +1,118 @@ | ||
1 | +/** | |
2 | + * A daemon to simulate power button of Android | |
3 | + * | |
4 | + * Copyright (C) 2011 The Android-x86 Open Source Project | |
5 | + * | |
6 | + * by Chih-Wei Huang <cwhuang@linux.org.tw> | |
7 | + * | |
8 | + * Licensed under GPLv2 or later | |
9 | + * | |
10 | + **/ | |
11 | + | |
12 | +#define LOG_TAG "powerbtn" | |
13 | + | |
14 | +#include <sys/stat.h> | |
15 | +#include <poll.h> | |
16 | +#include <fcntl.h> | |
17 | +#include <errno.h> | |
18 | +#include <dirent.h> | |
19 | +#include <cutils/log.h> | |
20 | +#include <linux/input.h> | |
21 | +#include <linux/uinput.h> | |
22 | + | |
23 | +const int MAX_POWERBTNS = 3; | |
24 | + | |
25 | +int openfds(struct pollfd pfds[]) | |
26 | +{ | |
27 | + int cnt = 0; | |
28 | + const char *dirname = "/dev/input"; | |
29 | + DIR *dir; | |
30 | + if ((dir = opendir(dirname))) { | |
31 | + int fd; | |
32 | + struct dirent *de; | |
33 | + while ((de = readdir(dir))) { | |
34 | + if (de->d_name[0] != 'e') // eventX | |
35 | + continue; | |
36 | + char name[PATH_MAX]; | |
37 | + snprintf(name, PATH_MAX, "%s/%s", dirname, de->d_name); | |
38 | + fd = open(name, O_RDWR); | |
39 | + if (fd < 0) { | |
40 | + LOGE("could not open %s, %s", name, strerror(errno)); | |
41 | + continue; | |
42 | + } | |
43 | + name[sizeof(name) - 1] = '\0'; | |
44 | + if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { | |
45 | + LOGE("could not get device name for %s, %s\n", name, strerror(errno)); | |
46 | + name[0] = '\0'; | |
47 | + } | |
48 | + | |
49 | + // TODO: parse /etc/excluded-input-devices.xml | |
50 | + if (!strcmp(name, "Power Button")) { | |
51 | + LOGI("open %s(%s) ok", de->d_name, name); | |
52 | + pfds[cnt].events = POLLIN; | |
53 | + pfds[cnt++].fd = fd; | |
54 | + if (cnt < MAX_POWERBTNS) | |
55 | + continue; | |
56 | + else | |
57 | + break; | |
58 | + } | |
59 | + close(fd); | |
60 | + } | |
61 | + closedir(dir); | |
62 | + } | |
63 | + | |
64 | + return cnt; | |
65 | +} | |
66 | + | |
67 | +int main() | |
68 | +{ | |
69 | + struct pollfd pfds[MAX_POWERBTNS]; | |
70 | + int cnt = openfds(pfds); | |
71 | + int pollres; | |
72 | + | |
73 | + int ufd = open("/dev/uinput", O_WRONLY | O_NDELAY); | |
74 | + if (ufd >= 0) { | |
75 | + struct uinput_user_dev ud; | |
76 | + memset(&ud, 0, sizeof(ud)); | |
77 | + strcpy(ud.name, "Android Power Button"); | |
78 | + write(ufd, &ud, sizeof(ud)); | |
79 | + ioctl(ufd, UI_SET_EVBIT, EV_KEY); | |
80 | + ioctl(ufd, UI_SET_KEYBIT, KEY_POWER); | |
81 | + ioctl(ufd, UI_DEV_CREATE, 0); | |
82 | + } else { | |
83 | + LOGE("could not open uinput device: %s", strerror(errno)); | |
84 | + return -1; | |
85 | + } | |
86 | + | |
87 | + while ((pollres = poll(pfds, cnt, -1))) { | |
88 | + int i; | |
89 | + if (pollres < 0) { | |
90 | + LOGE("poll error: %s", strerror(errno)); | |
91 | + break; | |
92 | + } | |
93 | + for (i = 0; i < cnt; ++i) { | |
94 | + if (pfds[i].revents & POLLIN) { | |
95 | + struct input_event iev; | |
96 | + size_t res = read(pfds[i].fd, &iev, sizeof(iev)); | |
97 | + if (res < sizeof(iev)) { | |
98 | + LOGW("insufficient input data(%d)? fd=%d", res, pfds[i].fd); | |
99 | + continue; | |
100 | + } | |
101 | + LOGV("type=%d scancode=%d value=%d from fd=%d", iev.type, iev.code, iev.value, pfds[i].fd); | |
102 | + if (iev.type == EV_KEY) { | |
103 | + switch (iev.code) | |
104 | + { | |
105 | + case KEY_POWER: | |
106 | + if (!iev.value) | |
107 | + sleep(2); | |
108 | + break; | |
109 | + } | |
110 | + } | |
111 | + | |
112 | + write(ufd, &iev, sizeof(iev)); | |
113 | + } | |
114 | + } | |
115 | + } | |
116 | + | |
117 | + return 0; | |
118 | +} |