am 32592270: am 64e13880: Merge "bundle init.rc contents with its service"
* commit '32592270d40d6060e19aa97949aee72c8aca0807':
bundle init.rc contents with its service
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index c208575..ef8db06 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -312,7 +312,6 @@
dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
dump_file("KERNEL SYNC", "/d/sync");
- dump_file("KERNEL BLUEDROID", "/d/bluedroid");
run_command("PROCESSES", 10, "ps", "-P", NULL);
run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
@@ -420,8 +419,6 @@
run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime",
"-b", "all", "-d", "*:v", NULL);
- for_each_userid(do_dump_settings, NULL);
-
/* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
@@ -437,6 +434,8 @@
run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
+ run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "connectivity", "--diag", NULL);
+
run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL);
run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL);
run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL);
@@ -540,6 +539,7 @@
run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL);
run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL);
run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL);
+ run_command("CHECKIN PACKAGE", 30, "dumpsys", "package", "--checkin", NULL);
printf("========================================================\n");
printf("== Running Application Activities\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 26bba1b..c5d3044 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,7 +26,6 @@
typedef void (for_each_pid_func)(int, const char *);
typedef void (for_each_tid_func)(int, int, const char *);
-typedef void (for_each_userid_func)(int);
/* prints the contents of a file */
int dump_file(const char *title, const char *path);
@@ -67,9 +66,6 @@
/* for each thread in the system, run the specified function */
void for_each_tid(for_each_tid_func func, const char *header);
-/* for each user id in the system, run the specified function */
-void for_each_userid(for_each_userid_func func, const char *header);
-
/* Displays a blocked processes in-kernel wait channel */
void show_wchan(int pid, int tid, const char *name);
@@ -79,9 +75,6 @@
/* Gets the dmesg output for the kernel */
void do_dmesg();
-/* Dumps settings for a given user id */
-void do_dump_settings(int userid);
-
/* Prints the contents of all the routing tables, both IPv4 and IPv6. */
void dump_route_tables();
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index fbb0331..0dd0c21 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -206,22 +206,6 @@
return;
}
-void do_dump_settings(int userid) {
- char title[255];
- char dbpath[255];
- char sql[255];
- sprintf(title, "SYSTEM SETTINGS (user %d)", userid);
- if (userid == 0) {
- strcpy(dbpath, "/data/data/com.android.providers.settings/databases/settings.db");
- strcpy(sql, "pragma user_version; select * from system; select * from secure; select * from global;");
- } else {
- sprintf(dbpath, "/data/system/users/%d/settings.db", userid);
- strcpy(sql, "pragma user_version; select * from system; select * from secure;");
- }
- run_command(title, 20, SU_PATH, "root", "sqlite3", dbpath, sql, NULL);
- return;
-}
-
void do_dmesg() {
printf("------ KERNEL LOG (dmesg) ------\n");
/* Get size of kernel buffer */
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 48efb28..7090b36 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -50,7 +50,7 @@
return -1;
}
- std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+ std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
@@ -80,7 +80,7 @@
int uninstall(const char *uuid, const char *pkgname, userid_t userid)
{
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
remove_profile_file(pkgname);
@@ -115,7 +115,7 @@
return -1;
}
- std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+ std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (stat(pkgdir, &s) < 0) return -1;
@@ -141,7 +141,7 @@
int delete_user_data(const char *uuid, const char *pkgname, userid_t userid)
{
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
return delete_dir_contents(pkgdir, 0, NULL);
@@ -149,7 +149,7 @@
int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
{
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
@@ -177,15 +177,48 @@
return 0;
}
-int move_user_data(const char *from_uuid, const char *to_uuid,
- const char *package_name, appid_t appid, const char* seinfo) {
+int copy_complete_app(const char *from_uuid, const char *to_uuid,
+ const char *package_name, const char *data_app_name, appid_t appid,
+ const char* seinfo) {
std::vector<userid_t> users = get_known_users(from_uuid);
- // Copy package private data for all known users
+ // Copy app
+ {
+ std::string from(create_data_app_package_path(from_uuid, data_app_name));
+ std::string to(create_data_app_package_path(to_uuid, data_app_name));
+ std::string to_parent(create_data_app_path(to_uuid));
+
+ char *argv[] = {
+ (char*) kCpPath,
+ (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+ (char*) "-p", /* preserve timestamps, ownership, and permissions */
+ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*) "-P", /* Do not follow symlinks [default] */
+ (char*) "-d", /* don't dereference symlinks */
+ (char*) from.c_str(),
+ (char*) to_parent.c_str()
+ };
+
+ LOG(DEBUG) << "Copying " << from << " to " << to;
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+
+ if (rc != 0) {
+ LOG(ERROR) << "Failed copying " << from << " to " << to
+ << ": status " << rc;
+ goto fail;
+ }
+
+ if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+ LOG(ERROR) << "Failed to restorecon " << to;
+ goto fail;
+ }
+ }
+
+ // Copy private data for all known users
for (auto user : users) {
- std::string from(create_package_data_path(from_uuid, package_name, user));
- std::string to(create_package_data_path(to_uuid, package_name, user));
- std::string to_user(create_data_user_path(to_uuid, user));
+ std::string from(create_data_user_package_path(from_uuid, user, package_name));
+ std::string to(create_data_user_package_path(to_uuid, user, package_name));
+ std::string to_parent(create_data_user_path(to_uuid, user));
// Data source may not exist for all users; that's okay
if (access(from.c_str(), F_OK) != 0) {
@@ -213,7 +246,7 @@
(char*) "-P", /* Do not follow symlinks [default] */
(char*) "-d", /* don't dereference symlinks */
(char*) from.c_str(),
- (char*) to_user.c_str()
+ (char*) to_parent.c_str()
};
LOG(DEBUG) << "Copying " << from << " to " << to;
@@ -224,26 +257,28 @@
<< ": status " << rc;
goto fail;
}
-
- if (restorecon_data(to_uuid, package_name, seinfo, uid) != 0) {
- LOG(ERROR) << "Failed to restorecon " << to;
- goto fail;
- }
}
- // Copy successful, so delete old data
- for (auto user : users) {
- std::string from(create_package_data_path(from_uuid, package_name, user));
- if (delete_dir_contents(from.c_str(), 1, NULL) != 0) {
- LOG(WARNING) << "Failed to delete " << from;
- }
+ if (restorecon_data(to_uuid, package_name, seinfo, multiuser_get_uid(0, appid)) != 0) {
+ LOG(ERROR) << "Failed to restorecon";
+ goto fail;
}
+
+ // We let the framework scan the new location and persist that before
+ // deleting the data in the old location; this ordering ensures that
+ // we can recover from things like battery pulls.
return 0;
fail:
// Nuke everything we might have already copied
+ {
+ std::string to(create_data_app_package_path(to_uuid, data_app_name));
+ if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
for (auto user : users) {
- std::string to(create_package_data_path(to_uuid, package_name, user));
+ std::string to(create_data_user_package_path(to_uuid, user, package_name));
if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
@@ -289,7 +324,7 @@
int delete_cache(const char *uuid, const char *pkgname, userid_t userid)
{
std::string _cachedir(
- create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
+ create_data_user_package_path(uuid, userid, pkgname) + CACHE_DIR_POSTFIX);
const char* cachedir = _cachedir.c_str();
/* delete contents, not the directory, no exceptions */
@@ -299,7 +334,7 @@
int delete_code_cache(const char *uuid, const char *pkgname, userid_t userid)
{
std::string _codecachedir(
- create_package_data_path(uuid, pkgname, userid) + CODE_CACHE_DIR_POSTFIX);
+ create_data_user_package_path(uuid, userid, pkgname) + CODE_CACHE_DIR_POSTFIX);
const char* codecachedir = _codecachedir.c_str();
struct stat s;
@@ -454,7 +489,7 @@
}
}
-int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath,
+int get_size(const char *uuid, const char *pkgname, int userid, const char *apkpath,
const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath,
const char *instruction_set, int64_t *_codesize, int64_t *_datasize,
int64_t *_cachesize, int64_t* _asecsize)
@@ -470,30 +505,38 @@
int64_t cachesize = 0;
int64_t asecsize = 0;
- /* count the source apk as code -- but only if it's not
- * on the /system partition and its not on the sdcard.
- */
+ /* count the source apk as code -- but only if it's not
+ * on the /system partition and its not on the sdcard. */
if (validate_system_app_path(apkpath) &&
strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
if (stat(apkpath, &s) == 0) {
codesize += stat_size(&s);
+ if (S_ISDIR(s.st_mode)) {
+ d = opendir(apkpath);
+ if (d != NULL) {
+ dfd = dirfd(d);
+ codesize += calculate_dir_size(dfd);
+ closedir(d);
+ }
+ }
}
}
- /* count the forward locked apk as code if it is given
- */
+
+ /* count the forward locked apk as code if it is given */
if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
if (stat(fwdlock_apkpath, &s) == 0) {
codesize += stat_size(&s);
}
}
- /* count the cached dexfile as code */
+
+ /* count the cached dexfile as code */
if (!create_cache_path(path, apkpath, instruction_set)) {
if (stat(path, &s) == 0) {
codesize += stat_size(&s);
}
}
- /* add in size of any libraries */
+ /* add in size of any libraries */
if (libdirpath != NULL && libdirpath[0] != '!') {
d = opendir(libdirpath);
if (d != NULL) {
@@ -503,68 +546,76 @@
}
}
- /* compute asec size if it is given
- */
+ /* compute asec size if it is given */
if (asecpath != NULL && asecpath[0] != '!') {
if (stat(asecpath, &s) == 0) {
asecsize += stat_size(&s);
}
}
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
- const char* pkgdir = _pkgdir.c_str();
-
- d = opendir(pkgdir);
- if (d == NULL) {
- goto done;
+ std::vector<userid_t> users;
+ if (userid == -1) {
+ users = get_known_users(uuid);
+ } else {
+ users.push_back(userid);
}
- dfd = dirfd(d);
- /* most stuff in the pkgdir is data, except for the "cache"
- * directory and below, which is cache, and the "lib" directory
- * and below, which is code...
- */
- while ((de = readdir(d))) {
- const char *name = de->d_name;
+ for (auto user : users) {
+ std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname));
+ const char* pkgdir = _pkgdir.c_str();
- if (de->d_type == DT_DIR) {
- int subfd;
- int64_t statsize = 0;
- int64_t dirsize = 0;
- /* always skip "." and ".." */
- if (name[0] == '.') {
- if (name[1] == 0) continue;
- if ((name[1] == '.') && (name[2] == 0)) continue;
- }
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- statsize = stat_size(&s);
- }
- subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
- if (subfd >= 0) {
- dirsize = calculate_dir_size(subfd);
- }
- if(!strcmp(name,"lib")) {
- codesize += dirsize + statsize;
- } else if(!strcmp(name,"cache")) {
- cachesize += dirsize + statsize;
+ d = opendir(pkgdir);
+ if (d == NULL) {
+ PLOG(WARNING) << "Failed to open " << pkgdir;
+ continue;
+ }
+ dfd = dirfd(d);
+
+ /* most stuff in the pkgdir is data, except for the "cache"
+ * directory and below, which is cache, and the "lib" directory
+ * and below, which is code...
+ */
+ while ((de = readdir(d))) {
+ const char *name = de->d_name;
+
+ if (de->d_type == DT_DIR) {
+ int subfd;
+ int64_t statsize = 0;
+ int64_t dirsize = 0;
+ /* always skip "." and ".." */
+ if (name[0] == '.') {
+ if (name[1] == 0) continue;
+ if ((name[1] == '.') && (name[2] == 0)) continue;
+ }
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+ statsize = stat_size(&s);
+ }
+ subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
+ if (subfd >= 0) {
+ dirsize = calculate_dir_size(subfd);
+ }
+ if(!strcmp(name,"lib")) {
+ codesize += dirsize + statsize;
+ } else if(!strcmp(name,"cache")) {
+ cachesize += dirsize + statsize;
+ } else {
+ datasize += dirsize + statsize;
+ }
+ } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
+ // This is the symbolic link to the application's library
+ // code. We'll count this as code instead of data, since
+ // it is not something that the app creates.
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+ codesize += stat_size(&s);
+ }
} else {
- datasize += dirsize + statsize;
- }
- } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
- // This is the symbolic link to the application's library
- // code. We'll count this as code instead of data, since
- // it is not something that the app creates.
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- codesize += stat_size(&s);
- }
- } else {
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- datasize += stat_size(&s);
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+ datasize += stat_size(&s);
+ }
}
}
+ closedir(d);
}
- closedir(d);
-done:
*_codesize = codesize;
*_datasize = datasize;
*_cachesize = cachesize;
@@ -1489,7 +1540,7 @@
struct stat s, libStat;
int rc = 0;
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userId));
+ std::string _pkgdir(create_data_user_package_path(uuid, userId, pkgname));
std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
const char* pkgdir = _pkgdir.c_str();
@@ -1680,7 +1731,7 @@
// Special case for owner on internal storage
if (uuid == nullptr) {
- std::string path(create_package_data_path(nullptr, pkgName, 0));
+ std::string path(create_data_user_package_path(nullptr, 0, pkgName));
if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) {
PLOG(ERROR) << "restorecon failed for " << path;
@@ -1758,6 +1809,31 @@
return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */);
}
+int link_file(const char* relative_path, const char* from_base, const char* to_base) {
+ char from_path[PKG_PATH_MAX];
+ char to_path[PKG_PATH_MAX];
+ snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
+ snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
+
+ if (validate_apk_path_subdirs(from_path)) {
+ ALOGE("invalid app data sub-path '%s' (bad prefix)\n", from_path);
+ return -1;
+ }
+
+ if (validate_apk_path_subdirs(to_path)) {
+ ALOGE("invalid app data sub-path '%s' (bad prefix)\n", to_path);
+ return -1;
+ }
+
+ const int ret = link(from_path, to_path);
+ if (ret < 0) {
+ ALOGE("link(%s, %s) failed : %s", from_path, to_path, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
const char *instruction_set) {
char *file_name_start;
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 3a86181..13e3168 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -124,10 +124,10 @@
return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
-static int do_mv_user_data(char **arg, char reply[REPLY_MAX] __unused)
+static int do_cp_complete_app(char **arg, char reply[REPLY_MAX] __unused)
{
- // from_uuid, to_uuid, pkgname, appid, seinfo
- return move_user_data(parse_null(arg[0]), parse_null(arg[1]), arg[2], atoi(arg[3]), arg[4]);
+ // from_uuid, to_uuid, package_name, data_app_name, appid, seinfo
+ return copy_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3], atoi(arg[4]), arg[5]);
}
static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused)
@@ -179,6 +179,12 @@
return rm_package_dir(arg[0]);
}
+static int do_link_file(char **arg, char reply[REPLY_MAX] __unused)
+{
+ /* relative_path, from_base, to_base */
+ return link_file(arg[0], arg[1], arg[2]);
+}
+
struct cmdinfo {
const char *name;
unsigned numargs;
@@ -200,7 +206,7 @@
{ "rmcodecache", 3, do_rm_code_cache },
{ "getsize", 8, do_get_size },
{ "rmuserdata", 3, do_rm_user_data },
- { "mvuserdata", 5, do_mv_user_data },
+ { "cpcompleteapp", 6, do_cp_complete_app },
{ "movefiles", 0, do_movefiles },
{ "linklib", 4, do_linklib },
{ "mkuserdata", 5, do_mk_user_data },
@@ -209,7 +215,8 @@
{ "idmap", 3, do_idmap },
{ "restorecondata", 4, do_restorecon_data },
{ "createoatdir", 2, do_create_oat_dir },
- { "rmpackagedir", 1, do_rm_package_dir},
+ { "rmpackagedir", 1, do_rm_package_dir },
+ { "linkfile", 3, do_link_file }
};
static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index f31bf4f..7ec5793 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -142,10 +142,6 @@
/* util.c */
-// TODO: rename to create_data_user_package_path
-std::string create_package_data_path(const char* volume_uuid,
- const char* package_name, userid_t user);
-
int create_pkg_path(char path[PKG_PATH_MAX],
const char *pkgname,
const char *postfix,
@@ -153,8 +149,15 @@
std::string create_data_path(const char* volume_uuid);
+std::string create_data_app_path(const char* volume_uuid);
+
+std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
+
std::string create_data_user_path(const char* volume_uuid, userid_t userid);
+std::string create_data_user_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name);
+
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
std::vector<userid_t> get_known_users(const char* volume_uuid);
@@ -200,6 +203,7 @@
int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
int validate_apk_path(const char *path);
+int validate_apk_path_subdirs(const char *path);
int append_and_increment(char** dst, const char* src, size_t* dst_size);
@@ -221,8 +225,9 @@
int delete_user_data(const char *uuid, const char *pkgname, userid_t userid);
int make_user_data(const char *uuid, const char *pkgname, uid_t uid,
userid_t userid, const char* seinfo);
-int move_user_data(const char* from_uuid, const char *to_uuid,
- const char *package_name, appid_t appid, const char* seinfo);
+int copy_complete_app(const char* from_uuid, const char *to_uuid,
+ const char *package_name, const char *data_app_name, appid_t appid,
+ const char* seinfo);
int make_user_config(userid_t userid);
int delete_user(const char *uuid, userid_t userid);
int delete_cache(const char *uuid, const char *pkgname, userid_t userid);
@@ -230,9 +235,11 @@
int move_dex(const char *src, const char *dst, const char *instruction_set);
int rm_dex(const char *path, const char *instruction_set);
int protect(char *pkgname, gid_t gid);
-int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath,
- const char *fwdlock_apkpath, const char *asecpath, const char *instruction_set,
- int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
+int get_size(const char *uuid, const char *pkgname, int userid,
+ const char *apkpath, const char *libdirpath,
+ const char *fwdlock_apkpath, const char *asecpath,
+ const char *instruction_set, int64_t *codesize, int64_t *datasize,
+ int64_t *cachesize, int64_t *asecsize);
int free_cache(const char *uuid, int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName,
const char *instruction_set, int dexopt_needed, bool vm_safe_mode,
@@ -248,3 +255,4 @@
const char *instruction_set);
int move_package_dir(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
const char *instruction_set);
+int link_file(const char *relative_path, const char *from_base, const char *to_base);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 4ce559d..5e397f9 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -455,6 +455,13 @@
create_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
}
+TEST_F(UtilsTest, CreateDataAppPath) {
+ EXPECT_EQ("/data/app", create_data_app_path(nullptr));
+
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app",
+ create_data_app_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
+}
+
TEST_F(UtilsTest, CreateDataUserPath) {
EXPECT_EQ("/data/data", create_data_user_path(nullptr, 0));
EXPECT_EQ("/data/user/10", create_data_user_path(nullptr, 10));
@@ -475,14 +482,21 @@
create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
}
-TEST_F(UtilsTest, CreatePackageDataPath) {
- EXPECT_EQ("/data/data/com.example", create_package_data_path(nullptr, "com.example", 0));
- EXPECT_EQ("/data/user/10/com.example", create_package_data_path(nullptr, "com.example", 10));
+TEST_F(UtilsTest, CreateDataAppPackagePath) {
+ EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example"));
+
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example",
+ create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example"));
+}
+
+TEST_F(UtilsTest, CreateDataUserPackagePath) {
+ EXPECT_EQ("/data/data/com.example", create_data_user_package_path(nullptr, 0, "com.example"));
+ EXPECT_EQ("/data/user/10/com.example", create_data_user_package_path(nullptr, 10, "com.example"));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0/com.example",
- create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 0));
+ create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10/com.example",
- create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 10));
+ create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
}
}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 5dfdf03..e58391f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -37,16 +37,31 @@
}
/**
+ * Create the path name where package app contents should be stored for
+ * the given volume UUID and package name. An empty UUID is assumed to
+ * be internal storage.
+ */
+std::string create_data_app_package_path(const char* volume_uuid,
+ const char* package_name) {
+ CHECK(is_valid_filename(package_name));
+ CHECK(is_valid_package_name(package_name) == 0);
+
+ return StringPrintf("%s/%s",
+ create_data_app_path(volume_uuid).c_str(), package_name);
+}
+
+/**
* Create the path name where package data should be stored for the given
* volume UUID, package name, and user ID. An empty UUID is assumed to be
* internal storage.
*/
-std::string create_package_data_path(const char* volume_uuid,
- const char* package_name, userid_t user) {
+std::string create_data_user_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name) {
CHECK(is_valid_filename(package_name));
CHECK(is_valid_package_name(package_name) == 0);
- return StringPrintf("%s/%s", create_data_user_path(volume_uuid, user).c_str(), package_name);
+ return StringPrintf("%s/%s",
+ create_data_user_path(volume_uuid, user).c_str(), package_name);
}
int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
@@ -56,7 +71,7 @@
return -1;
}
- std::string _tmp(create_package_data_path(nullptr, pkgname, userid) + postfix);
+ std::string _tmp(create_data_user_package_path(nullptr, userid, pkgname) + postfix);
const char* tmp = _tmp.c_str();
if (strlen(tmp) >= PKG_PATH_MAX) {
path[0] = '\0';
@@ -77,6 +92,13 @@
}
/**
+ * Create the path name for app data.
+ */
+std::string create_data_app_path(const char* volume_uuid) {
+ return StringPrintf("%s/app", create_data_path(volume_uuid).c_str());
+}
+
+/**
* Create the path name for user data for a certain userid.
*/
std::string create_data_user_path(const char* volume_uuid, userid_t userid) {
@@ -1021,15 +1043,13 @@
}
/**
- * Check whether path points to a valid path for an APK file. Only one level of
- * subdirectory names is allowed. Returns -1 when an invalid path is encountered
- * and 0 when a valid path is encountered.
+ * Check whether path points to a valid path for an APK file. The path must
+ * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
+ * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
+ * is encountered.
*/
-int validate_apk_path(const char *path)
-{
+static int validate_apk_path_internal(const char *path, int maxSubdirs) {
const dir_rec_t* dir = NULL;
- int maxSubdirs = 1;
-
if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
dir = &android_app_dir;
} else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
@@ -1038,7 +1058,9 @@
dir = &android_asec_dir;
} else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
dir = &android_mnt_expand_dir;
- maxSubdirs = 2;
+ if (maxSubdirs < 2) {
+ maxSubdirs = 2;
+ }
} else {
return -1;
}
@@ -1046,6 +1068,14 @@
return validate_path(dir, path, maxSubdirs);
}
+int validate_apk_path(const char* path) {
+ return validate_apk_path_internal(path, 1 /* maxSubdirs */);
+}
+
+int validate_apk_path_subdirs(const char* path) {
+ return validate_apk_path_internal(path, 3 /* maxSubdirs */);
+}
+
int append_and_increment(char** dst, const char* src, size_t* dst_size) {
ssize_t ret = strlcpy(*dst, src, *dst_size);
if (ret < 0 || (size_t) ret >= *dst_size) {
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 97fc47c..428b87c 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -146,6 +146,15 @@
break;
}
data.writeInt32(atoi(argv[optind++]));
+ } else if (strcmp(argv[optind], "i64") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no integer supplied for 'i64'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeInt64(atoll(argv[optind++]));
} else if (strcmp(argv[optind], "s16") == 0) {
optind++;
if (optind >= argc) {
@@ -155,6 +164,24 @@
break;
}
data.writeString16(String16(argv[optind++]));
+ } else if (strcmp(argv[optind], "f") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no number supplied for 'f'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeFloat(atof(argv[optind++]));
+ } else if (strcmp(argv[optind], "d") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no number supplied for 'd'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeDouble(atof(argv[optind++]));
} else if (strcmp(argv[optind], "null") == 0) {
optind++;
data.writeStrongBinder(NULL);
@@ -272,9 +299,12 @@
aout << "Usage: service [-h|-?]\n"
" service list\n"
" service check SERVICE\n"
- " service call SERVICE CODE [i32 INT | s16 STR] ...\n"
+ " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n"
"Options:\n"
- " i32: Write the integer INT into the send parcel.\n"
+ " i32: Write the 32-bit integer N into the send parcel.\n"
+ " i64: Write the 64-bit integer N into the send parcel.\n"
+ " f: Write the 32-bit single-precision number N into the send parcel.\n"
+ " d: Write the 64-bit double-precision number N into the send parcel.\n"
" s16: Write the UTF-16 string STR into the send parcel.\n";
// " intent: Write and Intent int the send parcel. ARGS can be\n"
// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
diff --git a/data/etc/android.hardware.fingerprint.xml b/data/etc/android.hardware.fingerprint.xml
new file mode 100644
index 0000000..3181e7e
--- /dev/null
+++ b/data/etc/android.hardware.fingerprint.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<!-- This is the standard set of features for a biometric fingerprint sensor. -->
+<permissions>
+ <feature name="android.hardware.fingerprint" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.hifi_sensors.xml b/data/etc/android.hardware.sensor.hifi_sensors.xml
new file mode 100644
index 0000000..bb3901c
--- /dev/null
+++ b/data/etc/android.hardware.sensor.hifi_sensors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- Feature for devices supporting hifi sensors. -->
+<permissions>
+ <feature name="android.hardware.sensor.hifi_sensors" />
+</permissions>
diff --git a/data/etc/android.software.midi.xml b/data/etc/android.software.midi.xml
new file mode 100644
index 0000000..a03cd55
--- /dev/null
+++ b/data/etc/android.software.midi.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<permissions>
+ <feature name="android.software.midi" />
+</permissions>
diff --git a/docs/Doxyfile b/docs/Doxyfile
deleted file mode 100644
index 46d6d84..0000000
--- a/docs/Doxyfile
+++ /dev/null
@@ -1,1902 +0,0 @@
-# Doxyfile 1.8.3.1
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
-
-PROJECT_NAME = "NDK API"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
-# a quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF = ""
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
-
-PROJECT_LOGO = logo.png
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY =
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF = "The $name class" \
- "The $name widget" \
- "The $name file" \
- is \
- provides \
- specifies \
- contains \
- represents \
- a \
- an \
- the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip. Note that you specify absolute paths here, but also
-# relative paths, which will be relative from the directory where doxygen is
-# started.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE = 4
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding
-# "class=itcl::class" will allow you to use the command class in the
-# itcl::class meaning.
-
-TCL_SUBST =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension,
-# and language is one of the parsers supported by doxygen: IDL, Java,
-# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
-# C++. For instance to make doxygen treat .inc files as Fortran files (default
-# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
-# that for custom extensions you also need to set FILE_PATTERNS otherwise the
-# files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you
-# can mix doxygen, HTML, and XML commands with Markdown formatting.
-# Disable only in case of backward compatibilities issues.
-
-MARKDOWN_SUPPORT = YES
-
-# When enabled doxygen tries to link words that correspond to documented classes,
-# or namespaces to their corresponding documentation. Such a link can be
-# prevented in individual cases by by putting a % sign in front of the word or
-# globally by setting AUTOLINK_SUPPORT to NO.
-
-AUTOLINK_SUPPORT = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES (the
-# default) will make doxygen replace the get and set methods by a property in
-# the documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
-# section (for LaTeX and RTF).
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields will be shown inline in the documentation
-# of the scope in which they are defined (i.e. file, namespace, or group
-# documentation), provided this scope is documented. If set to NO (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
-
-INLINE_SIMPLE_STRUCTS = NO
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT = NO
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-SYMBOL_CACHE_SIZE = 0
-
-# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
-# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
-# their name and scope. Since this can be an expensive process and often the
-# same symbol appear multiple times in the code, doxygen keeps a cache of
-# pre-resolved symbols. If the cache is too small doxygen will become slower.
-# If the cache is too large, memory is wasted. The cache size is given by this
-# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-LOOKUP_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
-# scope will be included in the documentation.
-
-EXTRACT_PACKAGE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = YES
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
-
-STRICT_PROTO_MATCHING = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if section-label ... \endif
-# and \cond section-label ... \endcond blocks.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES = 26
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page. This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
-
-LAYOUT_FILE =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files
-# containing the references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# requires the bibtex tool to be installed. See also
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
-# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
-# feature you need bibtex and perl available in the search path. Do not use
-# file names with spaces, bibtex cannot handle them.
-
-CITE_BIB_FILES =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR = YES
-
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
-WARN_NO_PARAMDOC = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT = ../include/android
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
-
-FILE_PATTERNS = *.c \
- *.cc \
- *.cxx \
- *.cpp \
- *.c++ \
- *.d \
- *.java \
- *.ii \
- *.ixx \
- *.ipp \
- *.i++ \
- *.inl \
- *.h \
- *.hh \
- *.hxx \
- *.hpp \
- *.h++ \
- *.idl \
- *.odl \
- *.cs \
- *.php \
- *.php3 \
- *.inc \
- *.m \
- *.markdown \
- *.md \
- *.mm \
- *.dox \
- *.py \
- *.f90 \
- *.f \
- *.for \
- *.vhd \
- *.vhdl
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output. If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page (index.html).
-# This can be useful if you have a project on for instance GitHub and want reuse
-# the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C, C++ and Fortran comments will always remain visible.
-
-STRIP_CODE_COMMENTS = NO
-
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code. Otherwise they will link to the documentation.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = NO
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT = $(HTML_OUTPUT)
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-# for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
-
-HTML_HEADER = $(HTML_HEADER)
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER = $(HTML_FOOTER)
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If left blank doxygen will
-# generate a default style sheet. Note that it is recommended to use
-# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
-# tag will in the future become obsolete.
-
-HTML_STYLESHEET =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
-# user-defined cascading style sheet that is included after the standard
-# style sheets created by doxygen. Using this option one can overrule
-# certain style aspects. This is preferred over using HTML_STYLESHEET
-# since it does not replace the standard style sheet and is therefor more
-# robust against future updates. Doxygen will copy the style sheet file to
-# the output directory.
-
-HTML_EXTRA_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
-# the files will be copied as-is; there are no commands or markers available.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the style sheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
-
-HTML_COLORSTYLE_SAT = 0
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
-
-HTML_TIMESTAMP = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
-# entries shown in the various tree structured indices initially; the user
-# can expand and collapse entries dynamically later on. Doxygen will expand
-# the tree to such a level that at most the specified number of entries are
-# visible (unless a fully collapsed tree already exceeds this amount).
-# So setting the number of entries 1 will produce a full collapsed tree by
-# default. 0 is a special value representing an infinite number of entries
-# and will result in a full expanded tree by default.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-
-GENERATE_DOCSET = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
-# identify the documentation publisher. This should be a reverse domain-name
-# style string, e.g. com.mycompany.MyDocSet.documentation.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS =
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
-# GENERATE_TREEVIEW to YES.
-
-DISABLE_INDEX = YES
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-# Since the tree basically has the same information as the tab index you
-# could consider to set DISABLE_INDEX to NO when enabling this option.
-
-GENERATE_TREEVIEW = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
-# values from appearing in the overview section.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you may also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
-# SVG. The default value is HTML-CSS, which is slower, but has the best
-# compatibility.
-
-MATHJAX_FORMAT = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to
-# the MathJax Content Delivery Network so you can quickly see the result without
-# installing MathJax. However, it is strongly recommended to install a local
-# copy of MathJax from http://www.mathjax.org before deployment.
-
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
-
-MATHJAX_EXTENSIONS =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-
-SEARCHENGINE = NO
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript.
-# There are two flavours of web server based search depending on the
-# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
-# searching and an index file used by the script. When EXTERNAL_SEARCH is
-# enabled the indexing and searching needs to be provided by external tools.
-# See the manual for details.
-
-SERVER_BASED_SEARCH = NO
-
-# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain
-# the search results. Doxygen ships with an example indexer (doxyindexer) and
-# search engine (doxysearch.cgi) which are based on the open source search engine
-# library Xapian. See the manual for configuration details.
-
-EXTERNAL_SEARCH = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will returned the search results when EXTERNAL_SEARCH is enabled.
-# Doxygen ships with an example search engine (doxysearch) which is based on
-# the open source search engine library Xapian. See the manual for configuration
-# details.
-
-SEARCHENGINE_URL =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-
-SEARCHDATA_FILE = searchdata.xml
-
-# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-
-EXTERNAL_SEARCH_ID =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
-# of to a relative location where the documentation can be found.
-# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
-
-EXTRA_SEARCH_MAPPINGS =
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE = a4
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
-# standard footer. Notice: only use this tag if you know what you are doing!
-
-LATEX_FOOTER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES = NO
-
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
-
-LATEX_SOURCE_CODE = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
-
-LATEX_BIB_STYLE = plain
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS = NO
-
-# Load style sheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
-# overrules the definition found in the source code.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles. For each
-# tag file the location of the external documentation should be added. The
-# format of a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths
-# or URLs. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
-# doxygen is run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
-
-CLASS_DIAGRAMS = NO
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
-
-DOT_NUM_THREADS = 0
-
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font you can specify
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find
-# the font, which can be done by putting it in a standard location or by setting
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
-# directory containing the font.
-
-DOT_FONTNAME = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside
-# the class node. If there are many fields or methods and many nodes the
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
-# threshold limits the number of items for each type to make the size more
-# managable. Set this to 0 for no limit. Note that the threshold may be
-# exceeded by 50% before the limit is enforced.
-
-UML_LIMIT_NUM_FIELDS = 10
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH = NO
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
-
-CALLER_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. If you choose svg you need to set
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible in IE 9+ (other browsers do not have this requirement).
-
-DOT_IMAGE_FORMAT = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-# Note that this requires a modern browser other than Internet Explorer.
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible. Older versions of IE do not have SVG support.
-
-INTERACTIVE_SVG = NO
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
-
-MSCFILE_DIRS =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP = YES
diff --git a/docs/Makefile b/docs/Makefile
deleted file mode 100644
index 5104d81..0000000
--- a/docs/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-HEADERS := $(wildcard ../include/android/*.h)
-
-all: html jd
-
-html: $(HEADERS) Doxyfile
- mkdir -p html
- doxygen
-
-jd: $(HEADERS) Doxyfile header.jd
- mkdir -p jd
- HTML_HEADER=header.jd HTML_FOOTER=footer.jd HTML_OUTPUT=jd doxygen
- for file in jd/*.html; do mv "$${file}" "$${file/.html/.jd}"; done
- rm -f jd/index.jd
diff --git a/docs/footer.jd b/docs/footer.jd
deleted file mode 100644
index e69de29..0000000
--- a/docs/footer.jd
+++ /dev/null
diff --git a/docs/header.jd b/docs/header.jd
deleted file mode 100644
index e50f41b..0000000
--- a/docs/header.jd
+++ /dev/null
@@ -1,3 +0,0 @@
-page.title=$title
-page.customHeadTag=<link rel="stylesheet" type="text/css" href="doxygen-dac.css">
-@jd:body
diff --git a/include/android/asset_manager.h b/include/android/asset_manager.h
index d654839..f5df46b 100644
--- a/include/android/asset_manager.h
+++ b/include/android/asset_manager.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Asset
- * @{
- */
-
-/**
- * @file asset_manager.h
- */
#ifndef ANDROID_ASSET_MANAGER_H
#define ANDROID_ASSET_MANAGER_H
@@ -31,49 +23,19 @@
#endif
struct AAssetManager;
-/**
- * {@link AAssetManager} provides access to an application's raw assets by
- * creating {@link AAsset} objects.
- *
- * AAssetManager is a wrapper to the low-level native implementation
- * of the java {@link AAssetManager}, a pointer can be obtained using
- * AAssetManager_fromJava().
- *
- * The asset hierarchy may be examined like a filesystem, using
- * {@link AAssetDir} objects to peruse a single directory.
- *
- * A native {@link AAssetManager} pointer may be shared across multiple threads.
- */
typedef struct AAssetManager AAssetManager;
struct AAssetDir;
-/**
- * {@link AAssetDir} provides access to a chunk of the asset hierarchy as if
- * it were a single directory. The contents are populated by the
- * {@link AAssetManager}.
- *
- * The list of files will be sorted in ascending order by ASCII value.
- */
typedef struct AAssetDir AAssetDir;
struct AAsset;
-/**
- * {@link AAsset} provides access to a read-only asset.
- *
- * {@link AAsset} objects are NOT thread-safe, and should not be shared across
- * threads.
- */
typedef struct AAsset AAsset;
-/** Available access modes for opening assets with {@link AAssetManager_open} */
+/* Available modes for opening assets */
enum {
- /** No specific information about how data will be accessed. **/
AASSET_MODE_UNKNOWN = 0,
- /** Read chunks, and seek forward and backward. */
AASSET_MODE_RANDOM = 1,
- /** Read sequentially, with an occasional forward seek. */
AASSET_MODE_STREAMING = 2,
- /** Caller plans to ask for a read-only buffer with all data. */
AASSET_MODE_BUFFER = 3
};
@@ -211,5 +173,3 @@
#endif
#endif // ANDROID_ASSET_MANAGER_H
-
-/** @} */
diff --git a/include/android/asset_manager_jni.h b/include/android/asset_manager_jni.h
index dcee17e..aec2d3c 100644
--- a/include/android/asset_manager_jni.h
+++ b/include/android/asset_manager_jni.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Asset
- * @{
- */
-
-/**
- * @file asset_manager_jni.h
- */
#ifndef ANDROID_ASSET_MANAGER_JNI_H
#define ANDROID_ASSET_MANAGER_JNI_H
@@ -46,5 +38,3 @@
#endif
#endif // ANDROID_ASSET_MANAGER_JNI_H
-
-/** @} */
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 261e64f..6e18763 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Bitmap
- * @{
- */
-
-/**
- * @file bitmap.h
- */
-
#ifndef ANDROID_BITMAP_H
#define ANDROID_BITMAP_H
@@ -33,52 +24,33 @@
extern "C" {
#endif
-/** AndroidBitmap functions result code. */
-enum {
- /** Operation was successful. */
- ANDROID_BITMAP_RESULT_SUCCESS = 0,
- /** Bad parameter. */
- ANDROID_BITMAP_RESULT_BAD_PARAMETER = -1,
- /** JNI exception occured. */
- ANDROID_BITMAP_RESULT_JNI_EXCEPTION = -2,
- /** Allocation failed. */
- ANDROID_BITMAP_RESULT_ALLOCATION_FAILED = -3,
-};
+#define ANDROID_BITMAP_RESULT_SUCCESS 0
+#define ANDROID_BITMAP_RESULT_BAD_PARAMETER -1
+#define ANDROID_BITMAP_RESULT_JNI_EXCEPTION -2
+#define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3
-/** Backward compatibility: this macro used to be misspelled. */
+/* Backward compatibility: this macro used to be misspelled. */
#define ANDROID_BITMAP_RESUT_SUCCESS ANDROID_BITMAP_RESULT_SUCCESS
-/** Bitmap pixel format. */
enum AndroidBitmapFormat {
- /** No format. */
ANDROID_BITMAP_FORMAT_NONE = 0,
- /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
- /** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
ANDROID_BITMAP_FORMAT_RGB_565 = 4,
- /** Red: 4 bits, Green: 4 bits, Blue: 4 bits, Alpha: 4 bits. **/
ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
- /** Deprecated. */
ANDROID_BITMAP_FORMAT_A_8 = 8,
};
-/** Bitmap info, see AndroidBitmap_getInfo(). */
typedef struct {
- /** The bitmap width in pixels. */
uint32_t width;
- /** The bitmap height in pixels. */
uint32_t height;
- /** The number of byte per row. */
uint32_t stride;
- /** The bitmap pixel format. See {@link AndroidBitmapFormat} */
int32_t format;
- /** Unused. */
uint32_t flags; // 0 for now
} AndroidBitmapInfo;
/**
- * Given a java bitmap object, fill out the AndroidBitmapInfo struct for it.
- * If the call fails, the info parameter will be ignored.
+ * Given a java bitmap object, fill out the AndroidBitmap struct for it.
+ * If the call fails, the info parameter will be ignored
*/
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info);
@@ -99,7 +71,7 @@
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
/**
- * Call this to balance a successful call to AndroidBitmap_lockPixels.
+ * Call this to balanace a successful call to AndroidBitmap_lockPixels
*/
int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
@@ -108,5 +80,3 @@
#endif
#endif
-
-/** @} */
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 287865e..7573cca 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Configuration
- * @{
- */
-
-/**
- * @file configuration.h
- */
-
#ifndef ANDROID_CONFIGURATION_H
#define ANDROID_CONFIGURATION_H
@@ -33,395 +24,103 @@
#endif
struct AConfiguration;
-/**
- * {@link AConfiguration} is an opaque type used to get and set
- * various subsystem configurations.
- *
- * A {@link AConfiguration} pointer can be obtained using:
- * - AConfiguration_new()
- * - AConfiguration_fromAssetManager()
- */
typedef struct AConfiguration AConfiguration;
-
-/**
- * Define flags and constants for various subsystem configurations.
- */
enum {
- /** Orientation: not specified. */
ACONFIGURATION_ORIENTATION_ANY = 0x0000,
- /**
- * Orientation: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#OrientationQualifier">port</a>
- * resource qualifier.
- */
ACONFIGURATION_ORIENTATION_PORT = 0x0001,
- /**
- * Orientation: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#OrientationQualifier">land</a>
- * resource qualifier.
- */
ACONFIGURATION_ORIENTATION_LAND = 0x0002,
- /** @deprecated Not currently supported or used. */
ACONFIGURATION_ORIENTATION_SQUARE = 0x0003,
- /** Touchscreen: not specified. */
ACONFIGURATION_TOUCHSCREEN_ANY = 0x0000,
- /**
- * Touchscreen: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a>
- * resource qualifier.
- */
ACONFIGURATION_TOUCHSCREEN_NOTOUCH = 0x0001,
- /** @deprecated Not currently supported or used. */
ACONFIGURATION_TOUCHSCREEN_STYLUS = 0x0002,
- /**
- * Touchscreen: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
- * resource qualifier.
- */
ACONFIGURATION_TOUCHSCREEN_FINGER = 0x0003,
- /** Density: default density. */
ACONFIGURATION_DENSITY_DEFAULT = 0,
- /**
- * Density: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">ldpi</a>
- * resource qualifier.
- */
ACONFIGURATION_DENSITY_LOW = 120,
- /**
- * Density: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">mdpi</a>
- * resource qualifier.
- */
ACONFIGURATION_DENSITY_MEDIUM = 160,
- /**
- * Density: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">tvdpi</a>
- * resource qualifier.
- */
ACONFIGURATION_DENSITY_TV = 213,
- /**
- * Density: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">hdpi</a>
- * resource qualifier.
- */
ACONFIGURATION_DENSITY_HIGH = 240,
- /**
- * Density: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">xhdpi</a>
- * resource qualifier.
- */
ACONFIGURATION_DENSITY_XHIGH = 320,
- /**
- * Density: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">xxhdpi</a>
- * resource qualifier.
- */
ACONFIGURATION_DENSITY_XXHIGH = 480,
- /**
- * Density: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">xxxhdpi</a>
- * resource qualifier.
- */
ACONFIGURATION_DENSITY_XXXHIGH = 640,
- /** Density: any density. */
ACONFIGURATION_DENSITY_ANY = 0xfffe,
- /** Density: no density specified. */
ACONFIGURATION_DENSITY_NONE = 0xffff,
- /** Keyboard: not specified. */
ACONFIGURATION_KEYBOARD_ANY = 0x0000,
- /**
- * Keyboard: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a>
- * resource qualifier.
- */
ACONFIGURATION_KEYBOARD_NOKEYS = 0x0001,
- /**
- * Keyboard: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a>
- * resource qualifier.
- */
ACONFIGURATION_KEYBOARD_QWERTY = 0x0002,
- /**
- * Keyboard: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
- * resource qualifier.
- */
ACONFIGURATION_KEYBOARD_12KEY = 0x0003,
- /** Navigation: not specified. */
ACONFIGURATION_NAVIGATION_ANY = 0x0000,
- /**
- * Navigation: value corresponding to the
- * <a href="@@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a>
- * resource qualifier.
- */
ACONFIGURATION_NAVIGATION_NONAV = 0x0001,
- /**
- * Navigation: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a>
- * resource qualifier.
- */
ACONFIGURATION_NAVIGATION_DPAD = 0x0002,
- /**
- * Navigation: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a>
- * resource qualifier.
- */
ACONFIGURATION_NAVIGATION_TRACKBALL = 0x0003,
- /**
- * Navigation: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
- * resource qualifier.
- */
ACONFIGURATION_NAVIGATION_WHEEL = 0x0004,
- /** Keyboard availability: not specified. */
ACONFIGURATION_KEYSHIDDEN_ANY = 0x0000,
- /**
- * Keyboard availability: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a>
- * resource qualifier.
- */
ACONFIGURATION_KEYSHIDDEN_NO = 0x0001,
- /**
- * Keyboard availability: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a>
- * resource qualifier.
- */
ACONFIGURATION_KEYSHIDDEN_YES = 0x0002,
- /**
- * Keyboard availability: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyssoft</a>
- * resource qualifier.
- */
ACONFIGURATION_KEYSHIDDEN_SOFT = 0x0003,
- /** Navigation availability: not specified. */
ACONFIGURATION_NAVHIDDEN_ANY = 0x0000,
- /**
- * Navigation availability: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a>
- * resource qualifier.
- */
ACONFIGURATION_NAVHIDDEN_NO = 0x0001,
- /**
- * Navigation availability: value corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
- * resource qualifier.
- */
ACONFIGURATION_NAVHIDDEN_YES = 0x0002,
- /** Screen size: not specified. */
ACONFIGURATION_SCREENSIZE_ANY = 0x00,
- /**
- * Screen size: value indicating the screen is at least
- * approximately 320x426 dp units, corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
- * resource qualifier.
- */
ACONFIGURATION_SCREENSIZE_SMALL = 0x01,
- /**
- * Screen size: value indicating the screen is at least
- * approximately 320x470 dp units, corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
- * resource qualifier.
- */
ACONFIGURATION_SCREENSIZE_NORMAL = 0x02,
- /**
- * Screen size: value indicating the screen is at least
- * approximately 480x640 dp units, corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a>
- * resource qualifier.
- */
ACONFIGURATION_SCREENSIZE_LARGE = 0x03,
- /**
- * Screen size: value indicating the screen is at least
- * approximately 720x960 dp units, corresponding to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a>
- * resource qualifier.
- */
ACONFIGURATION_SCREENSIZE_XLARGE = 0x04,
- /** Screen layout: not specified. */
ACONFIGURATION_SCREENLONG_ANY = 0x00,
- /**
- * Screen layout: value that corresponds to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
- * resource qualifier.
- */
ACONFIGURATION_SCREENLONG_NO = 0x1,
- /**
- * Screen layout: value that corresponds to the
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
- * resource qualifier.
- */
ACONFIGURATION_SCREENLONG_YES = 0x2,
- /** UI mode: not specified. */
+ ACONFIGURATION_SCREENROUND_ANY = 0x00,
+ ACONFIGURATION_SCREENROUND_NO = 0x1,
+ ACONFIGURATION_SCREENROUND_YES = 0x2,
+
ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
- /**
- * UI mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">no
- * UI mode type</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01,
- /**
- * UI mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02,
- /**
- * UI mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">car</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_TYPE_CAR = 0x03,
- /**
- * UI mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">television</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_TYPE_TELEVISION = 0x04,
- /**
- * UI mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_TYPE_APPLIANCE = 0x05,
- /**
- * UI mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_TYPE_WATCH = 0x06,
- /** UI night mode: not specified.*/
ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00,
- /**
- * UI night mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NightQualifier">notnight</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_NIGHT_NO = 0x1,
- /**
- * UI night mode: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NightQualifier">night</a> resource qualifier specified.
- */
ACONFIGURATION_UI_MODE_NIGHT_YES = 0x2,
- /** Screen width DPI: not specified. */
ACONFIGURATION_SCREEN_WIDTH_DP_ANY = 0x0000,
- /** Screen height DPI: not specified. */
ACONFIGURATION_SCREEN_HEIGHT_DP_ANY = 0x0000,
- /** Smallest screen width DPI: not specified.*/
ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY = 0x0000,
- /** Layout direction: not specified. */
ACONFIGURATION_LAYOUTDIR_ANY = 0x00,
- /**
- * Layout direction: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">ldltr</a> resource qualifier specified.
- */
ACONFIGURATION_LAYOUTDIR_LTR = 0x01,
- /**
- * Layout direction: value that corresponds to
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">ldrtl</a> resource qualifier specified.
- */
ACONFIGURATION_LAYOUTDIR_RTL = 0x02,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
- * configuration.
- */
ACONFIGURATION_MCC = 0x0001,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
- * configuration.
- */
ACONFIGURATION_MNC = 0x0002,
- /**
- * Bit mask for
- * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
- * configuration.
- */
ACONFIGURATION_LOCALE = 0x0004,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#TouchscreenQualifier">touchscreen</a>
- * configuration.
- */
ACONFIGURATION_TOUCHSCREEN = 0x0008,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">keyboard</a>
- * configuration.
- */
ACONFIGURATION_KEYBOARD = 0x0010,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyboardHidden</a>
- * configuration.
- */
ACONFIGURATION_KEYBOARD_HIDDEN = 0x0020,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">navigation</a>
- * configuration.
- */
ACONFIGURATION_NAVIGATION = 0x0040,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#OrientationQualifier">orientation</a>
- * configuration.
- */
ACONFIGURATION_ORIENTATION = 0x0080,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">density</a>
- * configuration.
- */
ACONFIGURATION_DENSITY = 0x0100,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">screen size</a>
- * configuration.
- */
ACONFIGURATION_SCREEN_SIZE = 0x0200,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#VersionQualifier">platform version</a>
- * configuration.
- */
ACONFIGURATION_VERSION = 0x0400,
- /**
- * Bit mask for screen layout configuration.
- */
ACONFIGURATION_SCREEN_LAYOUT = 0x0800,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">ui mode</a>
- * configuration.
- */
ACONFIGURATION_UI_MODE = 0x1000,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest screen width</a>
- * configuration.
- */
ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000,
- /**
- * Bit mask for
- * <a href="@dacRoot/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">layout direction</a>
- * configuration.
- */
ACONFIGURATION_LAYOUTDIR = 0x4000,
- /**
- * Constant used to to represent MNC (Mobile Network Code) zero.
- * 0 cannot be used, since it is used to represent an undefined MNC.
- */
+ ACONFIGURATION_SCREEN_ROUND = 0x8000,
+
ACONFIGURATION_MNC_ZERO = 0xffff,
};
@@ -438,7 +137,7 @@
/**
* Create and return a new AConfiguration based on the current configuration in
- * use in the given {@link AAssetManager}.
+ * use in the given AssetManager.
*/
void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am);
@@ -594,6 +293,16 @@
void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
/**
+ * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration.
+ */
+int32_t AConfiguration_getScreenRound(AConfiguration* config);
+
+/**
+ * Set the current screen round in the configuration.
+ */
+void AConfiguration_setScreenRound(AConfiguration* config, int32_t screenRound);
+
+/**
* Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration.
*/
int32_t AConfiguration_getUiModeType(AConfiguration* config);
@@ -689,5 +398,3 @@
#endif
#endif // ANDROID_CONFIGURATION_H
-
-/** @} */
diff --git a/include/android/input.h b/include/android/input.h
index b11af84..efbbb85 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Input
- * @{
- */
-
-/**
- * @file input.h
- */
-
#ifndef _ANDROID_INPUT_H
#define _ANDROID_INPUT_H
@@ -58,271 +49,247 @@
extern "C" {
#endif
-/**
+/*
* Key states (may be returned by queries about the current state of a
* particular key code, scan code or switch).
*/
enum {
- /** The key state is unknown or the requested key itself is not supported. */
+ /* The key state is unknown or the requested key itself is not supported. */
AKEY_STATE_UNKNOWN = -1,
- /** The key is up. */
+ /* The key is up. */
AKEY_STATE_UP = 0,
- /** The key is down. */
+ /* The key is down. */
AKEY_STATE_DOWN = 1,
- /** The key is down but is a virtual key press that is being emulated by the system. */
+ /* The key is down but is a virtual key press that is being emulated by the system. */
AKEY_STATE_VIRTUAL = 2
};
-/**
+/*
* Meta key / modifer state.
*/
enum {
- /** No meta keys are pressed. */
+ /* No meta keys are pressed. */
AMETA_NONE = 0,
- /** This mask is used to check whether one of the ALT meta keys is pressed. */
+ /* This mask is used to check whether one of the ALT meta keys is pressed. */
AMETA_ALT_ON = 0x02,
- /** This mask is used to check whether the left ALT meta key is pressed. */
+ /* This mask is used to check whether the left ALT meta key is pressed. */
AMETA_ALT_LEFT_ON = 0x10,
- /** This mask is used to check whether the right ALT meta key is pressed. */
+ /* This mask is used to check whether the right ALT meta key is pressed. */
AMETA_ALT_RIGHT_ON = 0x20,
- /** This mask is used to check whether one of the SHIFT meta keys is pressed. */
+ /* This mask is used to check whether one of the SHIFT meta keys is pressed. */
AMETA_SHIFT_ON = 0x01,
- /** This mask is used to check whether the left SHIFT meta key is pressed. */
+ /* This mask is used to check whether the left SHIFT meta key is pressed. */
AMETA_SHIFT_LEFT_ON = 0x40,
- /** This mask is used to check whether the right SHIFT meta key is pressed. */
+ /* This mask is used to check whether the right SHIFT meta key is pressed. */
AMETA_SHIFT_RIGHT_ON = 0x80,
- /** This mask is used to check whether the SYM meta key is pressed. */
+ /* This mask is used to check whether the SYM meta key is pressed. */
AMETA_SYM_ON = 0x04,
- /** This mask is used to check whether the FUNCTION meta key is pressed. */
+ /* This mask is used to check whether the FUNCTION meta key is pressed. */
AMETA_FUNCTION_ON = 0x08,
- /** This mask is used to check whether one of the CTRL meta keys is pressed. */
+ /* This mask is used to check whether one of the CTRL meta keys is pressed. */
AMETA_CTRL_ON = 0x1000,
- /** This mask is used to check whether the left CTRL meta key is pressed. */
+ /* This mask is used to check whether the left CTRL meta key is pressed. */
AMETA_CTRL_LEFT_ON = 0x2000,
- /** This mask is used to check whether the right CTRL meta key is pressed. */
+ /* This mask is used to check whether the right CTRL meta key is pressed. */
AMETA_CTRL_RIGHT_ON = 0x4000,
- /** This mask is used to check whether one of the META meta keys is pressed. */
+ /* This mask is used to check whether one of the META meta keys is pressed. */
AMETA_META_ON = 0x10000,
- /** This mask is used to check whether the left META meta key is pressed. */
+ /* This mask is used to check whether the left META meta key is pressed. */
AMETA_META_LEFT_ON = 0x20000,
- /** This mask is used to check whether the right META meta key is pressed. */
+ /* This mask is used to check whether the right META meta key is pressed. */
AMETA_META_RIGHT_ON = 0x40000,
- /** This mask is used to check whether the CAPS LOCK meta key is on. */
+ /* This mask is used to check whether the CAPS LOCK meta key is on. */
AMETA_CAPS_LOCK_ON = 0x100000,
- /** This mask is used to check whether the NUM LOCK meta key is on. */
+ /* This mask is used to check whether the NUM LOCK meta key is on. */
AMETA_NUM_LOCK_ON = 0x200000,
- /** This mask is used to check whether the SCROLL LOCK meta key is on. */
+ /* This mask is used to check whether the SCROLL LOCK meta key is on. */
AMETA_SCROLL_LOCK_ON = 0x400000,
};
-struct AInputEvent;
-/**
+/*
* Input events.
*
* Input events are opaque structures. Use the provided accessors functions to
* read their properties.
*/
+struct AInputEvent;
typedef struct AInputEvent AInputEvent;
-/**
+/*
* Input event types.
*/
enum {
- /** Indicates that the input event is a key event. */
+ /* Indicates that the input event is a key event. */
AINPUT_EVENT_TYPE_KEY = 1,
- /** Indicates that the input event is a motion event. */
+ /* Indicates that the input event is a motion event. */
AINPUT_EVENT_TYPE_MOTION = 2
};
-/**
+/*
* Key event actions.
*/
enum {
- /** The key has been pressed down. */
+ /* The key has been pressed down. */
AKEY_EVENT_ACTION_DOWN = 0,
- /** The key has been released. */
+ /* The key has been released. */
AKEY_EVENT_ACTION_UP = 1,
- /**
- * Multiple duplicate key events have occurred in a row, or a
- * complex string is being delivered. The repeat_count property
- * of the key event contains the number of times the given key
- * code should be executed.
+ /* Multiple duplicate key events have occurred in a row, or a complex string is
+ * being delivered. The repeat_count property of the key event contains the number
+ * of times the given key code should be executed.
*/
AKEY_EVENT_ACTION_MULTIPLE = 2
};
-/**
+/*
* Key event flags.
*/
enum {
- /** This mask is set if the device woke because of this key event. */
+ /* This mask is set if the device woke because of this key event. */
AKEY_EVENT_FLAG_WOKE_HERE = 0x1,
- /** This mask is set if the key event was generated by a software keyboard. */
+ /* This mask is set if the key event was generated by a software keyboard. */
AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2,
- /** This mask is set if we don't want the key event to cause us to leave touch mode. */
+ /* This mask is set if we don't want the key event to cause us to leave touch mode. */
AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4,
- /**
- * This mask is set if an event was known to come from a trusted
- * part of the system. That is, the event is known to come from
- * the user, and could not have been spoofed by a third party
- * component.
- */
+ /* This mask is set if an event was known to come from a trusted part
+ * of the system. That is, the event is known to come from the user,
+ * and could not have been spoofed by a third party component. */
AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8,
- /**
- * This mask is used for compatibility, to identify enter keys that are
+ /* This mask is used for compatibility, to identify enter keys that are
* coming from an IME whose enter key has been auto-labelled "next" or
* "done". This allows TextView to dispatch these as normal enter keys
* for old applications, but still do the appropriate action when
- * receiving them.
- */
+ * receiving them. */
AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10,
- /**
- * When associated with up key events, this indicates that the key press
+ /* When associated with up key events, this indicates that the key press
* has been canceled. Typically this is used with virtual touch screen
* keys, where the user can slide from the virtual key area on to the
* display: in that case, the application will receive a canceled up
* event and should not perform the action normally associated with the
* key. Note that for this to work, the application can not perform an
* action for a key until it receives an up or the long press timeout has
- * expired.
- */
+ * expired. */
AKEY_EVENT_FLAG_CANCELED = 0x20,
- /**
- * This key event was generated by a virtual (on-screen) hard key area.
+ /* This key event was generated by a virtual (on-screen) hard key area.
* Typically this is an area of the touchscreen, outside of the regular
- * display, dedicated to "hardware" buttons.
- */
+ * display, dedicated to "hardware" buttons. */
AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40,
- /**
- * This flag is set for the first key repeat that occurs after the
- * long press timeout.
- */
+ /* This flag is set for the first key repeat that occurs after the
+ * long press timeout. */
AKEY_EVENT_FLAG_LONG_PRESS = 0x80,
- /**
- * Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long
- * press action was executed while it was down.
- */
+ /* Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long
+ * press action was executed while it was down. */
AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100,
- /**
- * Set for AKEY_EVENT_ACTION_UP when this event's key code is still being
+ /* Set for AKEY_EVENT_ACTION_UP when this event's key code is still being
* tracked from its initial down. That is, somebody requested that tracking
* started on the key down and a long press has not caused
- * the tracking to be canceled.
- */
+ * the tracking to be canceled. */
AKEY_EVENT_FLAG_TRACKING = 0x200,
- /**
- * Set when a key event has been synthesized to implement default behavior
+ /* Set when a key event has been synthesized to implement default behavior
* for an event that the application did not handle.
* Fallback key events are generated by unhandled trackball motions
* (to emulate a directional keypad) and by certain unhandled key presses
* that are declared in the key map (such as special function numeric keypad
- * keys when numlock is off).
- */
+ * keys when numlock is off). */
AKEY_EVENT_FLAG_FALLBACK = 0x400,
};
-/**
- * Bit shift for the action bits holding the pointer index as
+/*
+ * Motion event actions.
+ */
+
+/* Bit shift for the action bits holding the pointer index as
* defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK.
*/
#define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8
-/** Motion event actions */
enum {
- /** Bit mask of the parts of the action code that are the action itself. */
+ /* Bit mask of the parts of the action code that are the action itself.
+ */
AMOTION_EVENT_ACTION_MASK = 0xff,
- /**
- * Bits in the action code that represent a pointer index, used with
+ /* Bits in the action code that represent a pointer index, used with
* AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting
* down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer
* index where the data for the pointer going up or down can be found.
*/
AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00,
- /** A pressed gesture has started, the motion contains the initial starting location. */
+ /* A pressed gesture has started, the motion contains the initial starting location.
+ */
AMOTION_EVENT_ACTION_DOWN = 0,
- /**
- * A pressed gesture has finished, the motion contains the final release location
+ /* A pressed gesture has finished, the motion contains the final release location
* as well as any intermediate points since the last down or move event.
*/
AMOTION_EVENT_ACTION_UP = 1,
- /**
- * A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and
+ /* A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and
* AMOTION_EVENT_ACTION_UP). The motion contains the most recent point, as well as
* any intermediate points since the last down or move event.
*/
AMOTION_EVENT_ACTION_MOVE = 2,
- /**
- * The current gesture has been aborted.
+ /* The current gesture has been aborted.
* You will not receive any more points in it. You should treat this as
* an up event, but not perform any action that you normally would.
*/
AMOTION_EVENT_ACTION_CANCEL = 3,
- /**
- * A movement has happened outside of the normal bounds of the UI element.
+ /* A movement has happened outside of the normal bounds of the UI element.
* This does not provide a full gesture, but only the initial location of the movement/touch.
*/
AMOTION_EVENT_ACTION_OUTSIDE = 4,
- /**
- * A non-primary pointer has gone down.
+ /* A non-primary pointer has gone down.
* The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
*/
AMOTION_EVENT_ACTION_POINTER_DOWN = 5,
- /**
- * A non-primary pointer has gone up.
+ /* A non-primary pointer has gone up.
* The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
*/
AMOTION_EVENT_ACTION_POINTER_UP = 6,
- /**
- * A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE).
+ /* A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE).
* The motion contains the most recent point, as well as any intermediate points since
* the last hover move event.
*/
AMOTION_EVENT_ACTION_HOVER_MOVE = 7,
- /**
- * The motion event contains relative vertical and/or horizontal scroll offsets.
+ /* The motion event contains relative vertical and/or horizontal scroll offsets.
* Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL
* and AMOTION_EVENT_AXIS_HSCROLL.
* The pointer may or may not be down when this event is dispatched.
@@ -331,19 +298,26 @@
*/
AMOTION_EVENT_ACTION_SCROLL = 8,
- /** The pointer is not down but has entered the boundaries of a window or view. */
+ /* The pointer is not down but has entered the boundaries of a window or view.
+ */
AMOTION_EVENT_ACTION_HOVER_ENTER = 9,
- /** The pointer is not down but has exited the boundaries of a window or view. */
+ /* The pointer is not down but has exited the boundaries of a window or view.
+ */
AMOTION_EVENT_ACTION_HOVER_EXIT = 10,
+
+ /* One or more buttons have been pressed. */
+ AMOTION_EVENT_ACTION_BUTTON_PRESS = 11,
+
+ /* One or more buttons have been released. */
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE = 12,
};
-/**
+/*
* Motion event flags.
*/
enum {
- /**
- * This flag indicates that the window that received this motion event is partly
+ /* This flag indicates that the window that received this motion event is partly
* or wholly obscured by another visible window above it. This flag is set to true
* even if the event did not directly pass through the obscured area.
* A security sensitive application can check this flag to identify situations in which
@@ -355,509 +329,173 @@
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1,
};
-/**
+/*
* Motion event edge touch flags.
*/
enum {
- /** No edges intersected. */
+ /* No edges intersected */
AMOTION_EVENT_EDGE_FLAG_NONE = 0,
- /** Flag indicating the motion event intersected the top edge of the screen. */
+ /* Flag indicating the motion event intersected the top edge of the screen. */
AMOTION_EVENT_EDGE_FLAG_TOP = 0x01,
- /** Flag indicating the motion event intersected the bottom edge of the screen. */
+ /* Flag indicating the motion event intersected the bottom edge of the screen. */
AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02,
- /** Flag indicating the motion event intersected the left edge of the screen. */
+ /* Flag indicating the motion event intersected the left edge of the screen. */
AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04,
- /** Flag indicating the motion event intersected the right edge of the screen. */
+ /* Flag indicating the motion event intersected the right edge of the screen. */
AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08
};
-/**
+/*
* Constants that identify each individual axis of a motion event.
- * @anchor AMOTION_EVENT_AXIS
+ * Refer to the documentation on the MotionEvent class for descriptions of each axis.
*/
enum {
- /**
- * Axis constant: X axis of a motion event.
- *
- * - For a touch screen, reports the absolute X screen position of the center of
- * the touch contact area. The units are display pixels.
- * - For a touch pad, reports the absolute X surface position of the center of the touch
- * contact area. The units are device-dependent.
- * - For a mouse, reports the absolute X screen position of the mouse pointer.
- * The units are display pixels.
- * - For a trackball, reports the relative horizontal displacement of the trackball.
- * The value is normalized to a range from -1.0 (left) to 1.0 (right).
- * - For a joystick, reports the absolute X position of the joystick.
- * The value is normalized to a range from -1.0 (left) to 1.0 (right).
- */
AMOTION_EVENT_AXIS_X = 0,
- /**
- * Axis constant: Y axis of a motion event.
- *
- * - For a touch screen, reports the absolute Y screen position of the center of
- * the touch contact area. The units are display pixels.
- * - For a touch pad, reports the absolute Y surface position of the center of the touch
- * contact area. The units are device-dependent.
- * - For a mouse, reports the absolute Y screen position of the mouse pointer.
- * The units are display pixels.
- * - For a trackball, reports the relative vertical displacement of the trackball.
- * The value is normalized to a range from -1.0 (up) to 1.0 (down).
- * - For a joystick, reports the absolute Y position of the joystick.
- * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near).
- */
AMOTION_EVENT_AXIS_Y = 1,
- /**
- * Axis constant: Pressure axis of a motion event.
- *
- * - For a touch screen or touch pad, reports the approximate pressure applied to the surface
- * by a finger or other tool. The value is normalized to a range from
- * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1
- * may be generated depending on the calibration of the input device.
- * - For a trackball, the value is set to 1 if the trackball button is pressed
- * or 0 otherwise.
- * - For a mouse, the value is set to 1 if the primary mouse button is pressed
- * or 0 otherwise.
- */
AMOTION_EVENT_AXIS_PRESSURE = 2,
- /**
- * Axis constant: Size axis of a motion event.
- *
- * - For a touch screen or touch pad, reports the approximate size of the contact area in
- * relation to the maximum detectable size for the device. The value is normalized
- * to a range from 0 (smallest detectable size) to 1 (largest detectable size),
- * although it is not a linear scale. This value is of limited use.
- * To obtain calibrated size information, see
- * {@link AMOTION_EVENT_AXIS_TOUCH_MAJOR} or {@link AMOTION_EVENT_AXIS_TOOL_MAJOR}.
- */
AMOTION_EVENT_AXIS_SIZE = 3,
- /**
- * Axis constant: TouchMajor axis of a motion event.
- *
- * - For a touch screen, reports the length of the major axis of an ellipse that
- * represents the touch area at the point of contact.
- * The units are display pixels.
- * - For a touch pad, reports the length of the major axis of an ellipse that
- * represents the touch area at the point of contact.
- * The units are device-dependent.
- */
AMOTION_EVENT_AXIS_TOUCH_MAJOR = 4,
- /**
- * Axis constant: TouchMinor axis of a motion event.
- *
- * - For a touch screen, reports the length of the minor axis of an ellipse that
- * represents the touch area at the point of contact.
- * The units are display pixels.
- * - For a touch pad, reports the length of the minor axis of an ellipse that
- * represents the touch area at the point of contact.
- * The units are device-dependent.
- *
- * When the touch is circular, the major and minor axis lengths will be equal to one another.
- */
AMOTION_EVENT_AXIS_TOUCH_MINOR = 5,
- /**
- * Axis constant: ToolMajor axis of a motion event.
- *
- * - For a touch screen, reports the length of the major axis of an ellipse that
- * represents the size of the approaching finger or tool used to make contact.
- * - For a touch pad, reports the length of the major axis of an ellipse that
- * represents the size of the approaching finger or tool used to make contact.
- * The units are device-dependent.
- *
- * When the touch is circular, the major and minor axis lengths will be equal to one another.
- *
- * The tool size may be larger than the touch size since the tool may not be fully
- * in contact with the touch sensor.
- */
AMOTION_EVENT_AXIS_TOOL_MAJOR = 6,
- /**
- * Axis constant: ToolMinor axis of a motion event.
- *
- * - For a touch screen, reports the length of the minor axis of an ellipse that
- * represents the size of the approaching finger or tool used to make contact.
- * - For a touch pad, reports the length of the minor axis of an ellipse that
- * represents the size of the approaching finger or tool used to make contact.
- * The units are device-dependent.
- *
- * When the touch is circular, the major and minor axis lengths will be equal to one another.
- *
- * The tool size may be larger than the touch size since the tool may not be fully
- * in contact with the touch sensor.
- */
AMOTION_EVENT_AXIS_TOOL_MINOR = 7,
- /**
- * Axis constant: Orientation axis of a motion event.
- *
- * - For a touch screen or touch pad, reports the orientation of the finger
- * or tool in radians relative to the vertical plane of the device.
- * An angle of 0 radians indicates that the major axis of contact is oriented
- * upwards, is perfectly circular or is of unknown orientation. A positive angle
- * indicates that the major axis of contact is oriented to the right. A negative angle
- * indicates that the major axis of contact is oriented to the left.
- * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
- * (finger pointing fully right).
- * - For a stylus, the orientation indicates the direction in which the stylus
- * is pointing in relation to the vertical axis of the current orientation of the screen.
- * The range is from -PI radians to PI radians, where 0 is pointing up,
- * -PI/2 radians is pointing left, -PI or PI radians is pointing down, and PI/2 radians
- * is pointing right. See also {@link AMOTION_EVENT_AXIS_TILT}.
- */
AMOTION_EVENT_AXIS_ORIENTATION = 8,
- /**
- * Axis constant: Vertical Scroll axis of a motion event.
- *
- * - For a mouse, reports the relative movement of the vertical scroll wheel.
- * The value is normalized to a range from -1.0 (down) to 1.0 (up).
- *
- * This axis should be used to scroll views vertically.
- */
AMOTION_EVENT_AXIS_VSCROLL = 9,
- /**
- * Axis constant: Horizontal Scroll axis of a motion event.
- *
- * - For a mouse, reports the relative movement of the horizontal scroll wheel.
- * The value is normalized to a range from -1.0 (left) to 1.0 (right).
- *
- * This axis should be used to scroll views horizontally.
- */
AMOTION_EVENT_AXIS_HSCROLL = 10,
- /**
- * Axis constant: Z axis of a motion event.
- *
- * - For a joystick, reports the absolute Z position of the joystick.
- * The value is normalized to a range from -1.0 (high) to 1.0 (low).
- * <em>On game pads with two analog joysticks, this axis is often reinterpreted
- * to report the absolute X position of the second joystick instead.</em>
- */
AMOTION_EVENT_AXIS_Z = 11,
- /**
- * Axis constant: X Rotation axis of a motion event.
- *
- * - For a joystick, reports the absolute rotation angle about the X axis.
- * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
- */
AMOTION_EVENT_AXIS_RX = 12,
- /**
- * Axis constant: Y Rotation axis of a motion event.
- *
- * - For a joystick, reports the absolute rotation angle about the Y axis.
- * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
- */
AMOTION_EVENT_AXIS_RY = 13,
- /**
- * Axis constant: Z Rotation axis of a motion event.
- *
- * - For a joystick, reports the absolute rotation angle about the Z axis.
- * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
- * On game pads with two analog joysticks, this axis is often reinterpreted
- * to report the absolute Y position of the second joystick instead.
- */
AMOTION_EVENT_AXIS_RZ = 14,
- /**
- * Axis constant: Hat X axis of a motion event.
- *
- * - For a joystick, reports the absolute X position of the directional hat control.
- * The value is normalized to a range from -1.0 (left) to 1.0 (right).
- */
AMOTION_EVENT_AXIS_HAT_X = 15,
- /**
- * Axis constant: Hat Y axis of a motion event.
- *
- * - For a joystick, reports the absolute Y position of the directional hat control.
- * The value is normalized to a range from -1.0 (up) to 1.0 (down).
- */
AMOTION_EVENT_AXIS_HAT_Y = 16,
- /**
- * Axis constant: Left Trigger axis of a motion event.
- *
- * - For a joystick, reports the absolute position of the left trigger control.
- * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
- */
AMOTION_EVENT_AXIS_LTRIGGER = 17,
- /**
- * Axis constant: Right Trigger axis of a motion event.
- *
- * - For a joystick, reports the absolute position of the right trigger control.
- * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
- */
AMOTION_EVENT_AXIS_RTRIGGER = 18,
- /**
- * Axis constant: Throttle axis of a motion event.
- *
- * - For a joystick, reports the absolute position of the throttle control.
- * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed).
- */
AMOTION_EVENT_AXIS_THROTTLE = 19,
- /**
- * Axis constant: Rudder axis of a motion event.
- *
- * - For a joystick, reports the absolute position of the rudder control.
- * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
- */
AMOTION_EVENT_AXIS_RUDDER = 20,
- /**
- * Axis constant: Wheel axis of a motion event.
- *
- * - For a joystick, reports the absolute position of the steering wheel control.
- * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
- */
AMOTION_EVENT_AXIS_WHEEL = 21,
- /**
- * Axis constant: Gas axis of a motion event.
- *
- * - For a joystick, reports the absolute position of the gas (accelerator) control.
- * The value is normalized to a range from 0.0 (no acceleration)
- * to 1.0 (maximum acceleration).
- */
AMOTION_EVENT_AXIS_GAS = 22,
- /**
- * Axis constant: Brake axis of a motion event.
- *
- * - For a joystick, reports the absolute position of the brake control.
- * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking).
- */
AMOTION_EVENT_AXIS_BRAKE = 23,
- /**
- * Axis constant: Distance axis of a motion event.
- *
- * - For a stylus, reports the distance of the stylus from the screen.
- * A value of 0.0 indicates direct contact and larger values indicate increasing
- * distance from the surface.
- */
AMOTION_EVENT_AXIS_DISTANCE = 24,
- /**
- * Axis constant: Tilt axis of a motion event.
- *
- * - For a stylus, reports the tilt angle of the stylus in radians where
- * 0 radians indicates that the stylus is being held perpendicular to the
- * surface, and PI/2 radians indicates that the stylus is being held flat
- * against the surface.
- */
AMOTION_EVENT_AXIS_TILT = 25,
- /**
- * Axis constant: Generic 1 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_1 = 32,
- /**
- * Axis constant: Generic 2 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_2 = 33,
- /**
- * Axis constant: Generic 3 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_3 = 34,
- /**
- * Axis constant: Generic 4 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_4 = 35,
- /**
- * Axis constant: Generic 5 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_5 = 36,
- /**
- * Axis constant: Generic 6 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_6 = 37,
- /**
- * Axis constant: Generic 7 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_7 = 38,
- /**
- * Axis constant: Generic 8 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_8 = 39,
- /**
- * Axis constant: Generic 9 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_9 = 40,
- /**
- * Axis constant: Generic 10 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_10 = 41,
- /**
- * Axis constant: Generic 11 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_11 = 42,
- /**
- * Axis constant: Generic 12 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_12 = 43,
- /**
- * Axis constant: Generic 13 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_13 = 44,
- /**
- * Axis constant: Generic 14 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_14 = 45,
- /**
- * Axis constant: Generic 15 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_15 = 46,
- /**
- * Axis constant: Generic 16 axis of a motion event.
- * The interpretation of a generic axis is device-specific.
- */
AMOTION_EVENT_AXIS_GENERIC_16 = 47,
// NOTE: If you add a new axis here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
};
-/**
+/*
* Constants that identify buttons that are associated with motion events.
* Refer to the documentation on the MotionEvent class for descriptions of each button.
*/
enum {
- /** primary */
AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0,
- /** secondary */
AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1,
- /** tertiary */
AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2,
- /** back */
AMOTION_EVENT_BUTTON_BACK = 1 << 3,
- /** forward */
AMOTION_EVENT_BUTTON_FORWARD = 1 << 4,
+ AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5,
+ AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6,
};
-/**
+/*
* Constants that identify tool types.
* Refer to the documentation on the MotionEvent class for descriptions of each tool type.
*/
enum {
- /** unknown */
AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0,
- /** finger */
AMOTION_EVENT_TOOL_TYPE_FINGER = 1,
- /** stylus */
AMOTION_EVENT_TOOL_TYPE_STYLUS = 2,
- /** mouse */
AMOTION_EVENT_TOOL_TYPE_MOUSE = 3,
- /** eraser */
AMOTION_EVENT_TOOL_TYPE_ERASER = 4,
};
-/**
- * Input source masks.
+/*
+ * Input sources.
*
* Refer to the documentation on android.view.InputDevice for more details about input sources
* and their correct interpretation.
*/
enum {
- /** mask */
AINPUT_SOURCE_CLASS_MASK = 0x000000ff,
- /** none */
AINPUT_SOURCE_CLASS_NONE = 0x00000000,
- /** button */
AINPUT_SOURCE_CLASS_BUTTON = 0x00000001,
- /** pointer */
AINPUT_SOURCE_CLASS_POINTER = 0x00000002,
- /** navigation */
AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004,
- /** position */
AINPUT_SOURCE_CLASS_POSITION = 0x00000008,
- /** joystick */
AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010,
};
-/**
- * Input sources.
- */
enum {
- /** unknown */
AINPUT_SOURCE_UNKNOWN = 0x00000000,
- /** keyboard */
AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON,
- /** dpad */
AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON,
- /** gamepad */
AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON,
- /** touchscreen */
AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER,
- /** mouse */
AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER,
- /** stylus */
AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER,
- /** trackball */
+ AINPUT_SOURCE_BLUETOOTH_STYLUS = 0x00008000 | AINPUT_SOURCE_STYLUS,
AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
- /** touchpad */
AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
- /** navigation */
AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
- /** joystick */
AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
- /** any */
AINPUT_SOURCE_ANY = 0xffffff00,
};
-/**
+/*
* Keyboard types.
*
* Refer to the documentation on android.view.InputDevice for more details.
*/
enum {
- /** none */
AINPUT_KEYBOARD_TYPE_NONE = 0,
- /** non alphabetic */
AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1,
- /** alphabetic */
AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2,
};
-/**
+/*
* Constants used to retrieve information about the range of motion for a particular
* coordinate of a motion event.
*
* Refer to the documentation on android.view.InputDevice for more details about input sources
* and their correct interpretation.
*
- * @deprecated These constants are deprecated. Use {@link AMOTION_EVENT_AXIS AMOTION_EVENT_AXIS_*} constants instead.
+ * DEPRECATION NOTICE: These constants are deprecated. Use AMOTION_EVENT_AXIS_* constants instead.
*/
enum {
- /** x */
AINPUT_MOTION_RANGE_X = AMOTION_EVENT_AXIS_X,
- /** y */
AINPUT_MOTION_RANGE_Y = AMOTION_EVENT_AXIS_Y,
- /** pressure */
AINPUT_MOTION_RANGE_PRESSURE = AMOTION_EVENT_AXIS_PRESSURE,
- /** size */
AINPUT_MOTION_RANGE_SIZE = AMOTION_EVENT_AXIS_SIZE,
- /** touch major */
AINPUT_MOTION_RANGE_TOUCH_MAJOR = AMOTION_EVENT_AXIS_TOUCH_MAJOR,
- /** touch minor */
AINPUT_MOTION_RANGE_TOUCH_MINOR = AMOTION_EVENT_AXIS_TOUCH_MINOR,
- /** tool major */
AINPUT_MOTION_RANGE_TOOL_MAJOR = AMOTION_EVENT_AXIS_TOOL_MAJOR,
- /** tool minor */
AINPUT_MOTION_RANGE_TOOL_MINOR = AMOTION_EVENT_AXIS_TOOL_MINOR,
- /** orientation */
AINPUT_MOTION_RANGE_ORIENTATION = AMOTION_EVENT_AXIS_ORIENTATION,
-};
+} __attribute__ ((deprecated));
-/**
+/*
* Input event accessors.
*
* Note that most functions can only be used on input events that are of a given type.
@@ -866,10 +504,10 @@
/*** Accessors for all input events. ***/
-/** Get the input event type. */
+/* Get the input event type. */
int32_t AInputEvent_getType(const AInputEvent* event);
-/** Get the id for the device that an input event came from.
+/* Get the id for the device that an input event came from.
*
* Input events can be generated by multiple different input devices.
* Use the input device id to obtain information about the input
@@ -881,351 +519,272 @@
*/
int32_t AInputEvent_getDeviceId(const AInputEvent* event);
-/** Get the input event source. */
+/* Get the input event source. */
int32_t AInputEvent_getSource(const AInputEvent* event);
/*** Accessors for key events only. ***/
-/** Get the key event action. */
+/* Get the key event action. */
int32_t AKeyEvent_getAction(const AInputEvent* key_event);
-/** Get the key event flags. */
+/* Get the key event flags. */
int32_t AKeyEvent_getFlags(const AInputEvent* key_event);
-/**
- * Get the key code of the key event.
- * This is the physical key that was pressed, not the Unicode character.
- */
+/* Get the key code of the key event.
+ * This is the physical key that was pressed, not the Unicode character. */
int32_t AKeyEvent_getKeyCode(const AInputEvent* key_event);
-/**
- * Get the hardware key id of this key event.
- * These values are not reliable and vary from device to device.
- */
+/* Get the hardware key id of this key event.
+ * These values are not reliable and vary from device to device. */
int32_t AKeyEvent_getScanCode(const AInputEvent* key_event);
-/** Get the meta key state. */
+/* Get the meta key state. */
int32_t AKeyEvent_getMetaState(const AInputEvent* key_event);
-/**
- * Get the repeat count of the event.
+/* Get the repeat count of the event.
* For both key up an key down events, this is the number of times the key has
* repeated with the first down starting at 0 and counting up from there. For
- * multiple key events, this is the number of down/up pairs that have occurred.
- */
+ * multiple key events, this is the number of down/up pairs that have occurred. */
int32_t AKeyEvent_getRepeatCount(const AInputEvent* key_event);
-/**
- * Get the time of the most recent key down event, in the
+/* Get the time of the most recent key down event, in the
* java.lang.System.nanoTime() time base. If this is a down event,
* this will be the same as eventTime.
* Note that when chording keys, this value is the down time of the most recently
- * pressed key, which may not be the same physical key of this event.
- */
+ * pressed key, which may not be the same physical key of this event. */
int64_t AKeyEvent_getDownTime(const AInputEvent* key_event);
-/**
- * Get the time this event occurred, in the
- * java.lang.System.nanoTime() time base.
- */
+/* Get the time this event occurred, in the
+ * java.lang.System.nanoTime() time base. */
int64_t AKeyEvent_getEventTime(const AInputEvent* key_event);
/*** Accessors for motion events only. ***/
-/** Get the combined motion event action code and pointer index. */
+/* Get the combined motion event action code and pointer index. */
int32_t AMotionEvent_getAction(const AInputEvent* motion_event);
-/** Get the motion event flags. */
+/* Get the motion event flags. */
int32_t AMotionEvent_getFlags(const AInputEvent* motion_event);
-/**
- * Get the state of any meta / modifier keys that were in effect when the
- * event was generated.
- */
+/* Get the state of any meta / modifier keys that were in effect when the
+ * event was generated. */
int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
-/** Get the button state of all buttons that are pressed. */
+/* Get the button state of all buttons that are pressed. */
int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
-/**
- * Get a bitfield indicating which edges, if any, were touched by this motion event.
+/* Get a bitfield indicating which edges, if any, were touched by this motion event.
* For touch events, clients can use this to determine if the user's finger was
- * touching the edge of the display.
- */
+ * touching the edge of the display. */
int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event);
-/**
- * Get the time when the user originally pressed down to start a stream of
- * position events, in the java.lang.System.nanoTime() time base.
- */
+/* Get the time when the user originally pressed down to start a stream of
+ * position events, in the java.lang.System.nanoTime() time base. */
int64_t AMotionEvent_getDownTime(const AInputEvent* motion_event);
-/**
- * Get the time when this specific event was generated,
- * in the java.lang.System.nanoTime() time base.
- */
+/* Get the time when this specific event was generated,
+ * in the java.lang.System.nanoTime() time base. */
int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event);
-/**
- * Get the X coordinate offset.
+/* Get the X coordinate offset.
* For touch events on the screen, this is the delta that was added to the raw
* screen coordinates to adjust for the absolute position of the containing windows
- * and views.
- */
+ * and views. */
float AMotionEvent_getXOffset(const AInputEvent* motion_event);
-/**
- * Get the Y coordinate offset.
+/* Get the Y coordinate offset.
* For touch events on the screen, this is the delta that was added to the raw
* screen coordinates to adjust for the absolute position of the containing windows
- * and views.
- */
+ * and views. */
float AMotionEvent_getYOffset(const AInputEvent* motion_event);
-/**
- * Get the precision of the X coordinates being reported.
+/* Get the precision of the X coordinates being reported.
* You can multiply this number with an X coordinate sample to find the
- * actual hardware value of the X coordinate.
- */
+ * actual hardware value of the X coordinate. */
float AMotionEvent_getXPrecision(const AInputEvent* motion_event);
-/**
- * Get the precision of the Y coordinates being reported.
+/* Get the precision of the Y coordinates being reported.
* You can multiply this number with a Y coordinate sample to find the
- * actual hardware value of the Y coordinate.
- */
+ * actual hardware value of the Y coordinate. */
float AMotionEvent_getYPrecision(const AInputEvent* motion_event);
-/**
- * Get the number of pointers of data contained in this event.
- * Always >= 1.
- */
+/* Get the number of pointers of data contained in this event.
+ * Always >= 1. */
size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event);
-/**
- * Get the pointer identifier associated with a particular pointer
+/* Get the pointer identifier associated with a particular pointer
* data index in this event. The identifier tells you the actual pointer
* number associated with the data, accounting for individual pointers
- * going up and down since the start of the current gesture.
- */
+ * going up and down since the start of the current gesture. */
int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the tool type of a pointer for the given pointer index.
+/* Get the tool type of a pointer for the given pointer index.
* The tool type indicates the type of tool used to make contact such as a
- * finger or stylus, if known.
- */
+ * finger or stylus, if known. */
int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the original raw X coordinate of this event.
+/* Get the original raw X coordinate of this event.
* For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
- * and views.
- */
+ * and views. */
float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the original raw X coordinate of this event.
+/* Get the original raw X coordinate of this event.
* For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
- * and views.
- */
+ * and views. */
float AMotionEvent_getRawY(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current X coordinate of this event for the given pointer index.
+/* Get the current X coordinate of this event for the given pointer index.
* Whole numbers are pixels; the value may have a fraction for input devices
- * that are sub-pixel precise.
- */
+ * that are sub-pixel precise. */
float AMotionEvent_getX(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current Y coordinate of this event for the given pointer index.
+/* Get the current Y coordinate of this event for the given pointer index.
* Whole numbers are pixels; the value may have a fraction for input devices
- * that are sub-pixel precise.
- */
+ * that are sub-pixel precise. */
float AMotionEvent_getY(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current pressure of this event for the given pointer index.
+/* Get the current pressure of this event for the given pointer index.
* The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
* although values higher than 1 may be generated depending on the calibration of
- * the input device.
- */
+ * the input device. */
float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current scaled value of the approximate size for the given pointer index.
+/* Get the current scaled value of the approximate size for the given pointer index.
* This represents some approximation of the area of the screen being
* pressed; the actual value in pixels corresponding to the
* touch is normalized with the device specific range of values
* and scaled to a value between 0 and 1. The value of size can be used to
- * determine fat touch events.
- */
+ * determine fat touch events. */
float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current length of the major axis of an ellipse that describes the touch area
- * at the point of contact for the given pointer index.
- */
+/* Get the current length of the major axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index. */
float AMotionEvent_getTouchMajor(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current length of the minor axis of an ellipse that describes the touch area
- * at the point of contact for the given pointer index.
- */
+/* Get the current length of the minor axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index. */
float AMotionEvent_getTouchMinor(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current length of the major axis of an ellipse that describes the size
+/* Get the current length of the major axis of an ellipse that describes the size
* of the approaching tool for the given pointer index.
* The tool area represents the estimated size of the finger or pen that is
- * touching the device independent of its actual touch area at the point of contact.
- */
+ * touching the device independent of its actual touch area at the point of contact. */
float AMotionEvent_getToolMajor(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current length of the minor axis of an ellipse that describes the size
+/* Get the current length of the minor axis of an ellipse that describes the size
* of the approaching tool for the given pointer index.
* The tool area represents the estimated size of the finger or pen that is
- * touching the device independent of its actual touch area at the point of contact.
- */
+ * touching the device independent of its actual touch area at the point of contact. */
float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_index);
-/**
- * Get the current orientation of the touch area and tool area in radians clockwise from
+/* Get the current orientation of the touch area and tool area in radians clockwise from
* vertical for the given pointer index.
* An angle of 0 degrees indicates that the major axis of contact is oriented
* upwards, is perfectly circular or is of unknown orientation. A positive angle
* indicates that the major axis of contact is oriented to the right. A negative angle
* indicates that the major axis of contact is oriented to the left.
* The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
- * (finger pointing fully right).
- */
+ * (finger pointing fully right). */
float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
-/** Get the value of the request axis for the given pointer index. */
+/* Get the value of the request axis for the given pointer index. */
float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
int32_t axis, size_t pointer_index);
-/**
- * Get the number of historical points in this event. These are movements that
+/* Get the number of historical points in this event. These are movements that
* have occurred between this event and the previous event. This only applies
* to AMOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0.
- * Historical samples are indexed from oldest to newest.
- */
+ * Historical samples are indexed from oldest to newest. */
size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event);
-/**
- * Get the time that a historical movement occurred between this event and
- * the previous event, in the java.lang.System.nanoTime() time base.
- */
+/* Get the time that a historical movement occurred between this event and
+ * the previous event, in the java.lang.System.nanoTime() time base. */
int64_t AMotionEvent_getHistoricalEventTime(const AInputEvent* motion_event,
size_t history_index);
-/**
- * Get the historical raw X coordinate of this event for the given pointer index that
+/* Get the historical raw X coordinate of this event for the given pointer index that
* occurred between this event and the previous motion event.
* For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
* and views.
* Whole numbers are pixels; the value may have a fraction for input devices
- * that are sub-pixel precise.
- */
+ * that are sub-pixel precise. */
float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical raw Y coordinate of this event for the given pointer index that
+/* Get the historical raw Y coordinate of this event for the given pointer index that
* occurred between this event and the previous motion event.
* For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
* and views.
* Whole numbers are pixels; the value may have a fraction for input devices
- * that are sub-pixel precise.
- */
+ * that are sub-pixel precise. */
float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical X coordinate of this event for the given pointer index that
+/* Get the historical X coordinate of this event for the given pointer index that
* occurred between this event and the previous motion event.
* Whole numbers are pixels; the value may have a fraction for input devices
- * that are sub-pixel precise.
- */
+ * that are sub-pixel precise. */
float AMotionEvent_getHistoricalX(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical Y coordinate of this event for the given pointer index that
+/* Get the historical Y coordinate of this event for the given pointer index that
* occurred between this event and the previous motion event.
* Whole numbers are pixels; the value may have a fraction for input devices
- * that are sub-pixel precise.
- */
+ * that are sub-pixel precise. */
float AMotionEvent_getHistoricalY(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical pressure of this event for the given pointer index that
+/* Get the historical pressure of this event for the given pointer index that
* occurred between this event and the previous motion event.
* The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
* although values higher than 1 may be generated depending on the calibration of
- * the input device.
- */
+ * the input device. */
float AMotionEvent_getHistoricalPressure(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the current scaled value of the approximate size for the given pointer index that
+/* Get the current scaled value of the approximate size for the given pointer index that
* occurred between this event and the previous motion event.
* This represents some approximation of the area of the screen being
* pressed; the actual value in pixels corresponding to the
* touch is normalized with the device specific range of values
* and scaled to a value between 0 and 1. The value of size can be used to
- * determine fat touch events.
- */
+ * determine fat touch events. */
float AMotionEvent_getHistoricalSize(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical length of the major axis of an ellipse that describes the touch area
+/* Get the historical length of the major axis of an ellipse that describes the touch area
* at the point of contact for the given pointer index that
- * occurred between this event and the previous motion event.
- */
+ * occurred between this event and the previous motion event. */
float AMotionEvent_getHistoricalTouchMajor(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical length of the minor axis of an ellipse that describes the touch area
+/* Get the historical length of the minor axis of an ellipse that describes the touch area
* at the point of contact for the given pointer index that
- * occurred between this event and the previous motion event.
- */
+ * occurred between this event and the previous motion event. */
float AMotionEvent_getHistoricalTouchMinor(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical length of the major axis of an ellipse that describes the size
+/* Get the historical length of the major axis of an ellipse that describes the size
* of the approaching tool for the given pointer index that
* occurred between this event and the previous motion event.
* The tool area represents the estimated size of the finger or pen that is
- * touching the device independent of its actual touch area at the point of contact.
- */
+ * touching the device independent of its actual touch area at the point of contact. */
float AMotionEvent_getHistoricalToolMajor(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical length of the minor axis of an ellipse that describes the size
+/* Get the historical length of the minor axis of an ellipse that describes the size
* of the approaching tool for the given pointer index that
* occurred between this event and the previous motion event.
* The tool area represents the estimated size of the finger or pen that is
- * touching the device independent of its actual touch area at the point of contact.
- */
+ * touching the device independent of its actual touch area at the point of contact. */
float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical orientation of the touch area and tool area in radians clockwise from
+/* Get the historical orientation of the touch area and tool area in radians clockwise from
* vertical for the given pointer index that
* occurred between this event and the previous motion event.
* An angle of 0 degrees indicates that the major axis of contact is oriented
@@ -1233,54 +792,51 @@
* indicates that the major axis of contact is oriented to the right. A negative angle
* indicates that the major axis of contact is oriented to the left.
* The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
- * (finger pointing fully right).
- */
+ * (finger pointing fully right). */
float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
-/**
- * Get the historical value of the request axis for the given pointer index
- * that occurred between this event and the previous motion event.
- */
+/* Get the historical value of the request axis for the given pointer index
+ * that occurred between this event and the previous motion event. */
float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
int32_t axis, size_t pointer_index, size_t history_index);
-struct AInputQueue;
-/**
+/*
* Input queue
*
* An input queue is the facility through which you retrieve input
* events.
*/
+struct AInputQueue;
typedef struct AInputQueue AInputQueue;
-/**
+/*
* Add this input queue to a looper for processing. See
* ALooper_addFd() for information on the ident, callback, and data params.
*/
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
int ident, ALooper_callbackFunc callback, void* data);
-/**
+/*
* Remove the input queue from the looper it is currently attached to.
*/
void AInputQueue_detachLooper(AInputQueue* queue);
-/**
+/*
* Returns true if there are one or more events available in the
* input queue. Returns 1 if the queue has events; 0 if
* it does not have events; and a negative value if there is an error.
*/
int32_t AInputQueue_hasEvents(AInputQueue* queue);
-/**
+/*
* Returns the next available event from the queue. Returns a negative
* value if no events are available or an error has occurred.
*/
int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent);
-/**
+/*
* Sends the key for standard pre-dispatching -- that is, possibly deliver
* it to the current IME to be consumed before the app. Returns 0 if it
* was not pre-dispatched, meaning you can process it right now. If non-zero
@@ -1290,7 +846,7 @@
*/
int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event);
-/**
+/*
* Report that dispatching has finished with the given event.
* This must be called after receiving an event with AInputQueue_get_event().
*/
@@ -1301,5 +857,3 @@
#endif
#endif // _ANDROID_INPUT_H
-
-/** @} */
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index ec4b0c8..de9e735 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Input
- * @{
- */
-
-/**
- * @file keycodes.h
- */
-
#ifndef _ANDROID_KEYCODES_H
#define _ANDROID_KEYCODES_H
@@ -48,677 +39,278 @@
extern "C" {
#endif
-/**
+/*
* Key codes.
*/
enum {
- /** Unknown key code. */
AKEYCODE_UNKNOWN = 0,
- /** Soft Left key.
- * Usually situated below the display on phones and used as a multi-function
- * feature key for selecting a software defined function shown on the bottom left
- * of the display. */
AKEYCODE_SOFT_LEFT = 1,
- /** Soft Right key.
- * Usually situated below the display on phones and used as a multi-function
- * feature key for selecting a software defined function shown on the bottom right
- * of the display. */
AKEYCODE_SOFT_RIGHT = 2,
- /** Home key.
- * This key is handled by the framework and is never delivered to applications. */
AKEYCODE_HOME = 3,
- /** Back key. */
AKEYCODE_BACK = 4,
- /** Call key. */
AKEYCODE_CALL = 5,
- /** End Call key. */
AKEYCODE_ENDCALL = 6,
- /** '0' key. */
AKEYCODE_0 = 7,
- /** '1' key. */
AKEYCODE_1 = 8,
- /** '2' key. */
AKEYCODE_2 = 9,
- /** '3' key. */
AKEYCODE_3 = 10,
- /** '4' key. */
AKEYCODE_4 = 11,
- /** '5' key. */
AKEYCODE_5 = 12,
- /** '6' key. */
AKEYCODE_6 = 13,
- /** '7' key. */
AKEYCODE_7 = 14,
- /** '8' key. */
AKEYCODE_8 = 15,
- /** '9' key. */
AKEYCODE_9 = 16,
- /** '*' key. */
AKEYCODE_STAR = 17,
- /** '#' key. */
AKEYCODE_POUND = 18,
- /** Directional Pad Up key.
- * May also be synthesized from trackball motions. */
AKEYCODE_DPAD_UP = 19,
- /** Directional Pad Down key.
- * May also be synthesized from trackball motions. */
AKEYCODE_DPAD_DOWN = 20,
- /** Directional Pad Left key.
- * May also be synthesized from trackball motions. */
AKEYCODE_DPAD_LEFT = 21,
- /** Directional Pad Right key.
- * May also be synthesized from trackball motions. */
AKEYCODE_DPAD_RIGHT = 22,
- /** Directional Pad Center key.
- * May also be synthesized from trackball motions. */
AKEYCODE_DPAD_CENTER = 23,
- /** Volume Up key.
- * Adjusts the speaker volume up. */
AKEYCODE_VOLUME_UP = 24,
- /** Volume Down key.
- * Adjusts the speaker volume down. */
AKEYCODE_VOLUME_DOWN = 25,
- /** Power key. */
AKEYCODE_POWER = 26,
- /** Camera key.
- * Used to launch a camera application or take pictures. */
AKEYCODE_CAMERA = 27,
- /** Clear key. */
AKEYCODE_CLEAR = 28,
- /** 'A' key. */
AKEYCODE_A = 29,
- /** 'B' key. */
AKEYCODE_B = 30,
- /** 'C' key. */
AKEYCODE_C = 31,
- /** 'D' key. */
AKEYCODE_D = 32,
- /** 'E' key. */
AKEYCODE_E = 33,
- /** 'F' key. */
AKEYCODE_F = 34,
- /** 'G' key. */
AKEYCODE_G = 35,
- /** 'H' key. */
AKEYCODE_H = 36,
- /** 'I' key. */
AKEYCODE_I = 37,
- /** 'J' key. */
AKEYCODE_J = 38,
- /** 'K' key. */
AKEYCODE_K = 39,
- /** 'L' key. */
AKEYCODE_L = 40,
- /** 'M' key. */
AKEYCODE_M = 41,
- /** 'N' key. */
AKEYCODE_N = 42,
- /** 'O' key. */
AKEYCODE_O = 43,
- /** 'P' key. */
AKEYCODE_P = 44,
- /** 'Q' key. */
AKEYCODE_Q = 45,
- /** 'R' key. */
AKEYCODE_R = 46,
- /** 'S' key. */
AKEYCODE_S = 47,
- /** 'T' key. */
AKEYCODE_T = 48,
- /** 'U' key. */
AKEYCODE_U = 49,
- /** 'V' key. */
AKEYCODE_V = 50,
- /** 'W' key. */
AKEYCODE_W = 51,
- /** 'X' key. */
AKEYCODE_X = 52,
- /** 'Y' key. */
AKEYCODE_Y = 53,
- /** 'Z' key. */
AKEYCODE_Z = 54,
- /** ',' key. */
AKEYCODE_COMMA = 55,
- /** '.' key. */
AKEYCODE_PERIOD = 56,
- /** Left Alt modifier key. */
AKEYCODE_ALT_LEFT = 57,
- /** Right Alt modifier key. */
AKEYCODE_ALT_RIGHT = 58,
- /** Left Shift modifier key. */
AKEYCODE_SHIFT_LEFT = 59,
- /** Right Shift modifier key. */
AKEYCODE_SHIFT_RIGHT = 60,
- /** Tab key. */
AKEYCODE_TAB = 61,
- /** Space key. */
AKEYCODE_SPACE = 62,
- /** Symbol modifier key.
- * Used to enter alternate symbols. */
AKEYCODE_SYM = 63,
- /** Explorer special function key.
- * Used to launch a browser application. */
AKEYCODE_EXPLORER = 64,
- /** Envelope special function key.
- * Used to launch a mail application. */
AKEYCODE_ENVELOPE = 65,
- /** Enter key. */
AKEYCODE_ENTER = 66,
- /** Backspace key.
- * Deletes characters before the insertion point, unlike {@link AKEYCODE_FORWARD_DEL}. */
AKEYCODE_DEL = 67,
- /** '`' (backtick) key. */
AKEYCODE_GRAVE = 68,
- /** '-'. */
AKEYCODE_MINUS = 69,
- /** '=' key. */
AKEYCODE_EQUALS = 70,
- /** '[' key. */
AKEYCODE_LEFT_BRACKET = 71,
- /** ']' key. */
AKEYCODE_RIGHT_BRACKET = 72,
- /** '\' key. */
AKEYCODE_BACKSLASH = 73,
- /** ';' key. */
AKEYCODE_SEMICOLON = 74,
- /** ''' (apostrophe) key. */
AKEYCODE_APOSTROPHE = 75,
- /** '/' key. */
AKEYCODE_SLASH = 76,
- /** '@' key. */
AKEYCODE_AT = 77,
- /** Number modifier key.
- * Used to enter numeric symbols.
- * This key is not {@link AKEYCODE_NUM_LOCK}; it is more like {@link AKEYCODE_ALT_LEFT}. */
AKEYCODE_NUM = 78,
- /** Headset Hook key.
- * Used to hang up calls and stop media. */
AKEYCODE_HEADSETHOOK = 79,
- /** Camera Focus key.
- * Used to focus the camera. */
- AKEYCODE_FOCUS = 80,
- /** '+' key. */
+ AKEYCODE_FOCUS = 80, // *Camera* focus
AKEYCODE_PLUS = 81,
- /** Menu key. */
AKEYCODE_MENU = 82,
- /** Notification key. */
AKEYCODE_NOTIFICATION = 83,
- /** Search key. */
AKEYCODE_SEARCH = 84,
- /** Play/Pause media key. */
AKEYCODE_MEDIA_PLAY_PAUSE= 85,
- /** Stop media key. */
AKEYCODE_MEDIA_STOP = 86,
- /** Play Next media key. */
AKEYCODE_MEDIA_NEXT = 87,
- /** Play Previous media key. */
AKEYCODE_MEDIA_PREVIOUS = 88,
- /** Rewind media key. */
AKEYCODE_MEDIA_REWIND = 89,
- /** Fast Forward media key. */
AKEYCODE_MEDIA_FAST_FORWARD = 90,
- /** Mute key.
- * Mutes the microphone, unlike {@link AKEYCODE_VOLUME_MUTE}. */
AKEYCODE_MUTE = 91,
- /** Page Up key. */
AKEYCODE_PAGE_UP = 92,
- /** Page Down key. */
AKEYCODE_PAGE_DOWN = 93,
- /** Picture Symbols modifier key.
- * Used to switch symbol sets (Emoji, Kao-moji). */
AKEYCODE_PICTSYMBOLS = 94,
- /** Switch Charset modifier key.
- * Used to switch character sets (Kanji, Katakana). */
AKEYCODE_SWITCH_CHARSET = 95,
- /** A Button key.
- * On a game controller, the A button should be either the button labeled A
- * or the first button on the bottom row of controller buttons. */
AKEYCODE_BUTTON_A = 96,
- /** B Button key.
- * On a game controller, the B button should be either the button labeled B
- * or the second button on the bottom row of controller buttons. */
AKEYCODE_BUTTON_B = 97,
- /** C Button key.
- * On a game controller, the C button should be either the button labeled C
- * or the third button on the bottom row of controller buttons. */
AKEYCODE_BUTTON_C = 98,
- /** X Button key.
- * On a game controller, the X button should be either the button labeled X
- * or the first button on the upper row of controller buttons. */
AKEYCODE_BUTTON_X = 99,
- /** Y Button key.
- * On a game controller, the Y button should be either the button labeled Y
- * or the second button on the upper row of controller buttons. */
AKEYCODE_BUTTON_Y = 100,
- /** Z Button key.
- * On a game controller, the Z button should be either the button labeled Z
- * or the third button on the upper row of controller buttons. */
AKEYCODE_BUTTON_Z = 101,
- /** L1 Button key.
- * On a game controller, the L1 button should be either the button labeled L1 (or L)
- * or the top left trigger button. */
AKEYCODE_BUTTON_L1 = 102,
- /** R1 Button key.
- * On a game controller, the R1 button should be either the button labeled R1 (or R)
- * or the top right trigger button. */
AKEYCODE_BUTTON_R1 = 103,
- /** L2 Button key.
- * On a game controller, the L2 button should be either the button labeled L2
- * or the bottom left trigger button. */
AKEYCODE_BUTTON_L2 = 104,
- /** R2 Button key.
- * On a game controller, the R2 button should be either the button labeled R2
- * or the bottom right trigger button. */
AKEYCODE_BUTTON_R2 = 105,
- /** Left Thumb Button key.
- * On a game controller, the left thumb button indicates that the left (or only)
- * joystick is pressed. */
AKEYCODE_BUTTON_THUMBL = 106,
- /** Right Thumb Button key.
- * On a game controller, the right thumb button indicates that the right
- * joystick is pressed. */
AKEYCODE_BUTTON_THUMBR = 107,
- /** Start Button key.
- * On a game controller, the button labeled Start. */
AKEYCODE_BUTTON_START = 108,
- /** Select Button key.
- * On a game controller, the button labeled Select. */
AKEYCODE_BUTTON_SELECT = 109,
- /** Mode Button key.
- * On a game controller, the button labeled Mode. */
AKEYCODE_BUTTON_MODE = 110,
- /** Escape key. */
AKEYCODE_ESCAPE = 111,
- /** Forward Delete key.
- * Deletes characters ahead of the insertion point, unlike {@link AKEYCODE_DEL}. */
AKEYCODE_FORWARD_DEL = 112,
- /** Left Control modifier key. */
AKEYCODE_CTRL_LEFT = 113,
- /** Right Control modifier key. */
AKEYCODE_CTRL_RIGHT = 114,
- /** Caps Lock key. */
AKEYCODE_CAPS_LOCK = 115,
- /** Scroll Lock key. */
AKEYCODE_SCROLL_LOCK = 116,
- /** Left Meta modifier key. */
AKEYCODE_META_LEFT = 117,
- /** Right Meta modifier key. */
AKEYCODE_META_RIGHT = 118,
- /** Function modifier key. */
AKEYCODE_FUNCTION = 119,
- /** System Request / Print Screen key. */
AKEYCODE_SYSRQ = 120,
- /** Break / Pause key. */
AKEYCODE_BREAK = 121,
- /** Home Movement key.
- * Used for scrolling or moving the cursor around to the start of a line
- * or to the top of a list. */
AKEYCODE_MOVE_HOME = 122,
- /** End Movement key.
- * Used for scrolling or moving the cursor around to the end of a line
- * or to the bottom of a list. */
AKEYCODE_MOVE_END = 123,
- /** Insert key.
- * Toggles insert / overwrite edit mode. */
AKEYCODE_INSERT = 124,
- /** Forward key.
- * Navigates forward in the history stack. Complement of {@link AKEYCODE_BACK}. */
AKEYCODE_FORWARD = 125,
- /** Play media key. */
AKEYCODE_MEDIA_PLAY = 126,
- /** Pause media key. */
AKEYCODE_MEDIA_PAUSE = 127,
- /** Close media key.
- * May be used to close a CD tray, for example. */
AKEYCODE_MEDIA_CLOSE = 128,
- /** Eject media key.
- * May be used to eject a CD tray, for example. */
AKEYCODE_MEDIA_EJECT = 129,
- /** Record media key. */
AKEYCODE_MEDIA_RECORD = 130,
- /** F1 key. */
AKEYCODE_F1 = 131,
- /** F2 key. */
AKEYCODE_F2 = 132,
- /** F3 key. */
AKEYCODE_F3 = 133,
- /** F4 key. */
AKEYCODE_F4 = 134,
- /** F5 key. */
AKEYCODE_F5 = 135,
- /** F6 key. */
AKEYCODE_F6 = 136,
- /** F7 key. */
AKEYCODE_F7 = 137,
- /** F8 key. */
AKEYCODE_F8 = 138,
- /** F9 key. */
AKEYCODE_F9 = 139,
- /** F10 key. */
AKEYCODE_F10 = 140,
- /** F11 key. */
AKEYCODE_F11 = 141,
- /** F12 key. */
AKEYCODE_F12 = 142,
- /** Num Lock key.
- * This is the Num Lock key; it is different from {@link AKEYCODE_NUM}.
- * This key alters the behavior of other keys on the numeric keypad. */
AKEYCODE_NUM_LOCK = 143,
- /** Numeric keypad '0' key. */
AKEYCODE_NUMPAD_0 = 144,
- /** Numeric keypad '1' key. */
AKEYCODE_NUMPAD_1 = 145,
- /** Numeric keypad '2' key. */
AKEYCODE_NUMPAD_2 = 146,
- /** Numeric keypad '3' key. */
AKEYCODE_NUMPAD_3 = 147,
- /** Numeric keypad '4' key. */
AKEYCODE_NUMPAD_4 = 148,
- /** Numeric keypad '5' key. */
AKEYCODE_NUMPAD_5 = 149,
- /** Numeric keypad '6' key. */
AKEYCODE_NUMPAD_6 = 150,
- /** Numeric keypad '7' key. */
AKEYCODE_NUMPAD_7 = 151,
- /** Numeric keypad '8' key. */
AKEYCODE_NUMPAD_8 = 152,
- /** Numeric keypad '9' key. */
AKEYCODE_NUMPAD_9 = 153,
- /** Numeric keypad '/' key (for division). */
AKEYCODE_NUMPAD_DIVIDE = 154,
- /** Numeric keypad '*' key (for multiplication). */
AKEYCODE_NUMPAD_MULTIPLY = 155,
- /** Numeric keypad '-' key (for subtraction). */
AKEYCODE_NUMPAD_SUBTRACT = 156,
- /** Numeric keypad '+' key (for addition). */
AKEYCODE_NUMPAD_ADD = 157,
- /** Numeric keypad '.' key (for decimals or digit grouping). */
AKEYCODE_NUMPAD_DOT = 158,
- /** Numeric keypad ',' key (for decimals or digit grouping). */
AKEYCODE_NUMPAD_COMMA = 159,
- /** Numeric keypad Enter key. */
AKEYCODE_NUMPAD_ENTER = 160,
- /** Numeric keypad '=' key. */
AKEYCODE_NUMPAD_EQUALS = 161,
- /** Numeric keypad '(' key. */
AKEYCODE_NUMPAD_LEFT_PAREN = 162,
- /** Numeric keypad ')' key. */
AKEYCODE_NUMPAD_RIGHT_PAREN = 163,
- /** Volume Mute key.
- * Mutes the speaker, unlike {@link AKEYCODE_MUTE}.
- * This key should normally be implemented as a toggle such that the first press
- * mutes the speaker and the second press restores the original volume. */
AKEYCODE_VOLUME_MUTE = 164,
- /** Info key.
- * Common on TV remotes to show additional information related to what is
- * currently being viewed. */
AKEYCODE_INFO = 165,
- /** Channel up key.
- * On TV remotes, increments the television channel. */
AKEYCODE_CHANNEL_UP = 166,
- /** Channel down key.
- * On TV remotes, decrements the television channel. */
AKEYCODE_CHANNEL_DOWN = 167,
- /** Zoom in key. */
AKEYCODE_ZOOM_IN = 168,
- /** Zoom out key. */
AKEYCODE_ZOOM_OUT = 169,
- /** TV key.
- * On TV remotes, switches to viewing live TV. */
AKEYCODE_TV = 170,
- /** Window key.
- * On TV remotes, toggles picture-in-picture mode or other windowing functions. */
AKEYCODE_WINDOW = 171,
- /** Guide key.
- * On TV remotes, shows a programming guide. */
AKEYCODE_GUIDE = 172,
- /** DVR key.
- * On some TV remotes, switches to a DVR mode for recorded shows. */
AKEYCODE_DVR = 173,
- /** Bookmark key.
- * On some TV remotes, bookmarks content or web pages. */
AKEYCODE_BOOKMARK = 174,
- /** Toggle captions key.
- * Switches the mode for closed-captioning text, for example during television shows. */
AKEYCODE_CAPTIONS = 175,
- /** Settings key.
- * Starts the system settings activity. */
AKEYCODE_SETTINGS = 176,
- /** TV power key.
- * On TV remotes, toggles the power on a television screen. */
AKEYCODE_TV_POWER = 177,
- /** TV input key.
- * On TV remotes, switches the input on a television screen. */
AKEYCODE_TV_INPUT = 178,
- /** Set-top-box power key.
- * On TV remotes, toggles the power on an external Set-top-box. */
AKEYCODE_STB_POWER = 179,
- /** Set-top-box input key.
- * On TV remotes, switches the input mode on an external Set-top-box. */
AKEYCODE_STB_INPUT = 180,
- /** A/V Receiver power key.
- * On TV remotes, toggles the power on an external A/V Receiver. */
AKEYCODE_AVR_POWER = 181,
- /** A/V Receiver input key.
- * On TV remotes, switches the input mode on an external A/V Receiver. */
AKEYCODE_AVR_INPUT = 182,
- /** Red "programmable" key.
- * On TV remotes, acts as a contextual/programmable key. */
AKEYCODE_PROG_RED = 183,
- /** Green "programmable" key.
- * On TV remotes, actsas a contextual/programmable key. */
AKEYCODE_PROG_GREEN = 184,
- /** Yellow "programmable" key.
- * On TV remotes, acts as a contextual/programmable key. */
AKEYCODE_PROG_YELLOW = 185,
- /** Blue "programmable" key.
- * On TV remotes, acts as a contextual/programmable key. */
AKEYCODE_PROG_BLUE = 186,
- /** App switch key.
- * Should bring up the application switcher dialog. */
AKEYCODE_APP_SWITCH = 187,
- /** Generic Game Pad Button #1.*/
AKEYCODE_BUTTON_1 = 188,
- /** Generic Game Pad Button #2.*/
AKEYCODE_BUTTON_2 = 189,
- /** Generic Game Pad Button #3.*/
AKEYCODE_BUTTON_3 = 190,
- /** Generic Game Pad Button #4.*/
AKEYCODE_BUTTON_4 = 191,
- /** Generic Game Pad Button #5.*/
AKEYCODE_BUTTON_5 = 192,
- /** Generic Game Pad Button #6.*/
AKEYCODE_BUTTON_6 = 193,
- /** Generic Game Pad Button #7.*/
AKEYCODE_BUTTON_7 = 194,
- /** Generic Game Pad Button #8.*/
AKEYCODE_BUTTON_8 = 195,
- /** Generic Game Pad Button #9.*/
AKEYCODE_BUTTON_9 = 196,
- /** Generic Game Pad Button #10.*/
AKEYCODE_BUTTON_10 = 197,
- /** Generic Game Pad Button #11.*/
AKEYCODE_BUTTON_11 = 198,
- /** Generic Game Pad Button #12.*/
AKEYCODE_BUTTON_12 = 199,
- /** Generic Game Pad Button #13.*/
AKEYCODE_BUTTON_13 = 200,
- /** Generic Game Pad Button #14.*/
AKEYCODE_BUTTON_14 = 201,
- /** Generic Game Pad Button #15.*/
AKEYCODE_BUTTON_15 = 202,
- /** Generic Game Pad Button #16.*/
AKEYCODE_BUTTON_16 = 203,
- /** Language Switch key.
- * Toggles the current input language such as switching between English and Japanese on
- * a QWERTY keyboard. On some devices, the same function may be performed by
- * pressing Shift+Spacebar. */
AKEYCODE_LANGUAGE_SWITCH = 204,
- /** Manner Mode key.
- * Toggles silent or vibrate mode on and off to make the device behave more politely
- * in certain settings such as on a crowded train. On some devices, the key may only
- * operate when long-pressed. */
AKEYCODE_MANNER_MODE = 205,
- /** 3D Mode key.
- * Toggles the display between 2D and 3D mode. */
AKEYCODE_3D_MODE = 206,
- /** Contacts special function key.
- * Used to launch an address book application. */
AKEYCODE_CONTACTS = 207,
- /** Calendar special function key.
- * Used to launch a calendar application. */
AKEYCODE_CALENDAR = 208,
- /** Music special function key.
- * Used to launch a music player application. */
AKEYCODE_MUSIC = 209,
- /** Calculator special function key.
- * Used to launch a calculator application. */
AKEYCODE_CALCULATOR = 210,
- /** Japanese full-width / half-width key. */
AKEYCODE_ZENKAKU_HANKAKU = 211,
- /** Japanese alphanumeric key. */
AKEYCODE_EISU = 212,
- /** Japanese non-conversion key. */
AKEYCODE_MUHENKAN = 213,
- /** Japanese conversion key. */
AKEYCODE_HENKAN = 214,
- /** Japanese katakana / hiragana key. */
AKEYCODE_KATAKANA_HIRAGANA = 215,
- /** Japanese Yen key. */
AKEYCODE_YEN = 216,
- /** Japanese Ro key. */
AKEYCODE_RO = 217,
- /** Japanese kana key. */
AKEYCODE_KANA = 218,
- /** Assist key.
- * Launches the global assist activity. Not delivered to applications. */
AKEYCODE_ASSIST = 219,
- /** Brightness Down key.
- * Adjusts the screen brightness down. */
AKEYCODE_BRIGHTNESS_DOWN = 220,
- /** Brightness Up key.
- * Adjusts the screen brightness up. */
AKEYCODE_BRIGHTNESS_UP = 221,
- /** Audio Track key.
- * Switches the audio tracks. */
AKEYCODE_MEDIA_AUDIO_TRACK = 222,
- /** Sleep key.
- * Puts the device to sleep. Behaves somewhat like {@link AKEYCODE_POWER} but it
- * has no effect if the device is already asleep. */
AKEYCODE_SLEEP = 223,
- /** Wakeup key.
- * Wakes up the device. Behaves somewhat like {@link AKEYCODE_POWER} but it
- * has no effect if the device is already awake. */
AKEYCODE_WAKEUP = 224,
- /** Pairing key.
- * Initiates peripheral pairing mode. Useful for pairing remote control
- * devices or game controllers, especially if no other input mode is
- * available. */
AKEYCODE_PAIRING = 225,
- /** Media Top Menu key.
- * Goes to the top of media menu. */
AKEYCODE_MEDIA_TOP_MENU = 226,
- /** '11' key. */
AKEYCODE_11 = 227,
- /** '12' key. */
AKEYCODE_12 = 228,
- /** Last Channel key.
- * Goes to the last viewed channel. */
AKEYCODE_LAST_CHANNEL = 229,
- /** TV data service key.
- * Displays data services like weather, sports. */
AKEYCODE_TV_DATA_SERVICE = 230,
- /** Voice Assist key.
- * Launches the global voice assist activity. Not delivered to applications. */
AKEYCODE_VOICE_ASSIST = 231,
- /** Radio key.
- * Toggles TV service / Radio service. */
AKEYCODE_TV_RADIO_SERVICE = 232,
- /** Teletext key.
- * Displays Teletext service. */
AKEYCODE_TV_TELETEXT = 233,
- /** Number entry key.
- * Initiates to enter multi-digit channel nubmber when each digit key is assigned
- * for selecting separate channel. Corresponds to Number Entry Mode (0x1D) of CEC
- * User Control Code. */
AKEYCODE_TV_NUMBER_ENTRY = 234,
- /** Analog Terrestrial key.
- * Switches to analog terrestrial broadcast service. */
AKEYCODE_TV_TERRESTRIAL_ANALOG = 235,
- /** Digital Terrestrial key.
- * Switches to digital terrestrial broadcast service. */
AKEYCODE_TV_TERRESTRIAL_DIGITAL = 236,
- /** Satellite key.
- * Switches to digital satellite broadcast service. */
AKEYCODE_TV_SATELLITE = 237,
- /** BS key.
- * Switches to BS digital satellite broadcasting service available in Japan. */
AKEYCODE_TV_SATELLITE_BS = 238,
- /** CS key.
- * Switches to CS digital satellite broadcasting service available in Japan. */
AKEYCODE_TV_SATELLITE_CS = 239,
- /** BS/CS key.
- * Toggles between BS and CS digital satellite services. */
AKEYCODE_TV_SATELLITE_SERVICE = 240,
- /** Toggle Network key.
- * Toggles selecting broacast services. */
AKEYCODE_TV_NETWORK = 241,
- /** Antenna/Cable key.
- * Toggles broadcast input source between antenna and cable. */
AKEYCODE_TV_ANTENNA_CABLE = 242,
- /** HDMI #1 key.
- * Switches to HDMI input #1. */
AKEYCODE_TV_INPUT_HDMI_1 = 243,
- /** HDMI #2 key.
- * Switches to HDMI input #2. */
AKEYCODE_TV_INPUT_HDMI_2 = 244,
- /** HDMI #3 key.
- * Switches to HDMI input #3. */
AKEYCODE_TV_INPUT_HDMI_3 = 245,
- /** HDMI #4 key.
- * Switches to HDMI input #4. */
AKEYCODE_TV_INPUT_HDMI_4 = 246,
- /** Composite #1 key.
- * Switches to composite video input #1. */
AKEYCODE_TV_INPUT_COMPOSITE_1 = 247,
- /** Composite #2 key.
- * Switches to composite video input #2. */
AKEYCODE_TV_INPUT_COMPOSITE_2 = 248,
- /** Component #1 key.
- * Switches to component video input #1. */
AKEYCODE_TV_INPUT_COMPONENT_1 = 249,
- /** Component #2 key.
- * Switches to component video input #2. */
AKEYCODE_TV_INPUT_COMPONENT_2 = 250,
- /** VGA #1 key.
- * Switches to VGA (analog RGB) input #1. */
AKEYCODE_TV_INPUT_VGA_1 = 251,
- /** Audio description key.
- * Toggles audio description off / on. */
AKEYCODE_TV_AUDIO_DESCRIPTION = 252,
- /** Audio description mixing volume up key.
- * Louden audio description volume as compared with normal audio volume. */
AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253,
- /** Audio description mixing volume down key.
- * Lessen audio description volume as compared with normal audio volume. */
AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254,
- /** Zoom mode key.
- * Changes Zoom mode (Normal, Full, Zoom, Wide-zoom, etc.) */
AKEYCODE_TV_ZOOM_MODE = 255,
- /** Contents menu key.
- * Goes to the title list. Corresponds to Contents Menu (0x0B) of CEC User Control
- * Code */
AKEYCODE_TV_CONTENTS_MENU = 256,
- /** Media context menu key.
- * Goes to the context menu of media contents. Corresponds to Media Context-sensitive
- * Menu (0x11) of CEC User Control Code. */
AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257,
- /** Timer programming key.
- * Goes to the timer recording menu. Corresponds to Timer Programming (0x54) of
- * CEC User Control Code. */
AKEYCODE_TV_TIMER_PROGRAMMING = 258,
- /** Help key. */
- AKEYCODE_HELP = 259
+ AKEYCODE_HELP = 259,
+ AKEYCODE_NAVIGATE_PREVIOUS = 260,
+ AKEYCODE_NAVIGATE_NEXT = 261,
+ AKEYCODE_NAVIGATE_IN = 262,
+ AKEYCODE_NAVIGATE_OUT = 263,
+ AKEYCODE_MEDIA_SKIP_FORWARD = 272,
+ AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
+ AKEYCODE_MEDIA_STEP_FORWARD = 274,
+ AKEYCODE_MEDIA_STEP_BACKWARD = 275
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
@@ -729,5 +321,3 @@
#endif
#endif // _ANDROID_KEYCODES_H
-
-/** @} */
diff --git a/include/android/looper.h b/include/android/looper.h
index 718f703..74c0383 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Looper
- * @{
- */
-
-/**
- * @file looper.h
- */
#ifndef ANDROID_LOOPER_H
#define ANDROID_LOOPER_H
@@ -30,7 +22,6 @@
extern "C" {
#endif
-struct ALooper;
/**
* ALooper
*
@@ -44,6 +35,7 @@
*
* A thread can have only one ALooper associated with it.
*/
+struct ALooper;
typedef struct ALooper ALooper;
/**
@@ -52,14 +44,13 @@
*/
ALooper* ALooper_forThread();
-/** Option for for ALooper_prepare(). */
enum {
/**
- * This looper will accept calls to ALooper_addFd() that do not
- * have a callback (that is provide NULL for the callback). In
- * this case the caller of ALooper_pollOnce() or ALooper_pollAll()
- * MUST check the return from these functions to discover when
- * data is available on such fds and process it.
+ * Option for ALooper_prepare: this looper will accept calls to
+ * ALooper_addFd() that do not have a callback (that is provide NULL
+ * for the callback). In this case the caller of ALooper_pollOnce()
+ * or ALooper_pollAll() MUST check the return from these functions to
+ * discover when data is available on such fds and process it.
*/
ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0
};
@@ -73,9 +64,9 @@
*/
ALooper* ALooper_prepare(int opts);
-/** Result from ALooper_pollOnce() and ALooper_pollAll(). */
enum {
/**
+ * Result from ALooper_pollOnce() and ALooper_pollAll():
* The poll was awoken using wake() before the timeout expired
* and no callbacks were executed and no other file descriptors were ready.
*/
@@ -185,12 +176,10 @@
*
* Returns ALOOPER_POLL_ERROR if an error occurred.
*
- * Returns a value >= 0 containing an identifier (the same identifier
- * `ident` passed to ALooper_addFd()) if its file descriptor has data
- * and it has no callback function (requiring the caller here to
- * handle it). In this (and only this) case outFd, outEvents and
- * outData will contain the poll events and data associated with the
- * fd, otherwise they will be set to NULL.
+ * Returns a value >= 0 containing an identifier if its file descriptor has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outFd, outEvents and outData will contain the poll
+ * events and data associated with the fd, otherwise they will be set to NULL.
*
* This method does not return until it has finished invoking the appropriate callbacks
* for all file descriptors that were signalled.
@@ -265,5 +254,3 @@
#endif
#endif // ANDROID_LOOPER_H
-
-/** @} */
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
new file mode 100644
index 0000000..6c718c9
--- /dev/null
+++ b/include/android/multinetwork.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_MULTINETWORK_H
+#define ANDROID_MULTINETWORK_H
+
+#include <netdb.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * The corresponding C type for android.net.Network#getNetworkHandle() return
+ * values. The Java signed long value can be safely cast to a net_handle_t:
+ *
+ * [C] ((net_handle_t) java_long_network_handle)
+ * [C++] static_cast<net_handle_t>(java_long_network_handle)
+ *
+ * as appropriate.
+ */
+typedef uint64_t net_handle_t;
+
+/**
+ * The value NETWORK_UNSPECIFIED indicates no specific network.
+ *
+ * For some functions (documented below), a previous binding may be cleared
+ * by an invocation with NETWORK_UNSPECIFIED.
+ *
+ * Depending on the context it may indicate an error. It is expressly
+ * not used to indicate some notion of the "current default network".
+ */
+#define NETWORK_UNSPECIFIED ((net_handle_t)0)
+
+
+/**
+ * All functions below that return an int return 0 on success or -1
+ * on failure with an appropriate errno value set.
+ */
+
+
+/**
+ * Set the network to be used by the given socket file descriptor.
+ *
+ * To clear a previous socket binding invoke with NETWORK_UNSPECIFIED.
+ *
+ * This is the equivalent of:
+ *
+ * [ android.net.Network#bindSocket() ]
+ * https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket)
+ */
+int android_setsocknetwork(net_handle_t network, int fd);
+
+
+/**
+ * Binds the current process to |network|. All sockets created in the future
+ * (and not explicitly bound via android_setsocknetwork()) will be bound to
+ * |network|. All host name resolutions will be limited to |network| as well.
+ * Note that if the network identified by |network| ever disconnects, all
+ * sockets created in this way will cease to work and all host name
+ * resolutions will fail. This is by design so an application doesn't
+ * accidentally use sockets it thinks are still bound to a particular network.
+ *
+ * To clear a previous process binding invoke with NETWORK_UNSPECIFIED.
+ *
+ * This is the equivalent of:
+ *
+ * [ android.net.ConnectivityManager#setProcessDefaultNetwork() ]
+ * https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network)
+ */
+int android_setprocnetwork(net_handle_t network);
+
+
+/**
+ * Perform hostname resolution via the DNS servers associated with |network|.
+ *
+ * All arguments (apart from |network|) are used identically as those passed
+ * to getaddrinfo(3). Return and error values are identical to those of
+ * getaddrinfo(3), and in particular gai_strerror(3) can be used as expected.
+ * Similar to getaddrinfo(3):
+ * - |hints| may be NULL (in which case man page documented defaults apply)
+ * - either |node| or |service| may be NULL, but not both
+ * - |res| must not be NULL
+ *
+ * This is the equivalent of:
+ *
+ * [ android.net.Network#getAllByName() ]
+ * https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String)
+ */
+int android_getaddrinfofornetwork(net_handle_t network,
+ const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **res);
+
+__END_DECLS
+
+#endif // ANDROID_MULTINETWORK_H
diff --git a/include/android/native_activity.h b/include/android/native_activity.h
index d3d99cf..bc70f88 100644
--- a/include/android/native_activity.h
+++ b/include/android/native_activity.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
- * @file native_activity.h
- */
#ifndef ANDROID_NATIVE_ACTIVITY_H
#define ANDROID_NATIVE_ACTIVITY_H
@@ -39,9 +31,6 @@
extern "C" {
#endif
-/**
- * {@link ANativeActivityCallbacks}
- */
struct ANativeActivityCallbacks;
/**
@@ -86,17 +75,17 @@
* Path to this application's internal data directory.
*/
const char* internalDataPath;
-
+
/**
* Path to this application's external (removable/mountable) data directory.
*/
const char* externalDataPath;
-
+
/**
* The platform's SDK version code.
*/
int32_t sdkVersion;
-
+
/**
* This is the native instance of the application. It is not used by
* the framework, but can be set by the application to its own instance
@@ -130,13 +119,13 @@
* for more information.
*/
void (*onStart)(ANativeActivity* activity);
-
+
/**
* NativeActivity has resumed. See Java documentation for Activity.onResume()
* for more information.
*/
void (*onResume)(ANativeActivity* activity);
-
+
/**
* Framework is asking NativeActivity to save its current instance state.
* See Java documentation for Activity.onSaveInstanceState() for more
@@ -147,19 +136,19 @@
* entities (pointers to memory, file descriptors, etc).
*/
void* (*onSaveInstanceState)(ANativeActivity* activity, size_t* outSize);
-
+
/**
* NativeActivity has paused. See Java documentation for Activity.onPause()
* for more information.
*/
void (*onPause)(ANativeActivity* activity);
-
+
/**
* NativeActivity has stopped. See Java documentation for Activity.onStop()
* for more information.
*/
void (*onStop)(ANativeActivity* activity);
-
+
/**
* NativeActivity is being destroyed. See Java documentation for Activity.onDestroy()
* for more information.
@@ -171,7 +160,7 @@
* for example, to pause a game when it loses input focus.
*/
void (*onWindowFocusChanged)(ANativeActivity* activity, int hasFocus);
-
+
/**
* The drawing window for this native activity has been created. You
* can use the given native window object to start drawing.
@@ -202,13 +191,13 @@
* returning from here.
*/
void (*onNativeWindowDestroyed)(ANativeActivity* activity, ANativeWindow* window);
-
+
/**
* The input queue for this native activity's window has been created.
* You can use the given input queue to start retrieving input events.
*/
void (*onInputQueueCreated)(ANativeActivity* activity, AInputQueue* queue);
-
+
/**
* The input queue for this native activity's window is being destroyed.
* You should no longer try to reference this object upon returning from this
@@ -284,17 +273,7 @@
* API for documentation.
*/
enum {
- /**
- * Implicit request to show the input window, not as the result
- * of a direct request by the user.
- */
ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001,
-
- /**
- * The user has forced the input method open (such as by
- * long-pressing menu) so it should not be closed until they
- * explicitly do so.
- */
ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002,
};
@@ -311,15 +290,7 @@
* API for documentation.
*/
enum {
- /**
- * The soft input window should only be hidden if it was not
- * explicitly shown by the user.
- */
ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001,
- /**
- * The soft input window should normally be hidden, unless it was
- * originally shown with {@link ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED}.
- */
ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002,
};
@@ -337,4 +308,3 @@
#endif // ANDROID_NATIVE_ACTIVITY_H
-/** @} */
diff --git a/include/android/native_window.h b/include/android/native_window.h
index cf07f1a..2f4f2d3 100644
--- a/include/android/native_window.h
+++ b/include/android/native_window.h
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
- * @file native_window.h
- */
-
#ifndef ANDROID_NATIVE_WINDOW_H
#define ANDROID_NATIVE_WINDOW_H
@@ -32,31 +23,18 @@
extern "C" {
#endif
-/**
+/*
* Pixel formats that a window can use.
*/
enum {
- /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
WINDOW_FORMAT_RGBA_8888 = 1,
- /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Unused: 8 bits. **/
WINDOW_FORMAT_RGBX_8888 = 2,
- /** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
WINDOW_FORMAT_RGB_565 = 4,
};
struct ANativeWindow;
-/**
- * {@link ANativeWindow} is opaque type that provides access to a native window.
- *
- * A pointer can be obtained using ANativeWindow_fromSurface().
- */
typedef struct ANativeWindow ANativeWindow;
-/**
- * {@link ANativeWindow} is a struct that represents a windows buffer.
- *
- * A pointer can be obtained using ANativeWindow_lock().
- */
typedef struct ANativeWindow_Buffer {
// The number of pixels that are show horizontally.
int32_t width;
@@ -73,7 +51,7 @@
// The actual bits.
void* bits;
-
+
// Do not touch.
uint32_t reserved[6];
} ANativeWindow_Buffer;
@@ -89,25 +67,25 @@
*/
void ANativeWindow_release(ANativeWindow* window);
-/**
+/*
* Return the current width in pixels of the window surface. Returns a
* negative value on error.
*/
int32_t ANativeWindow_getWidth(ANativeWindow* window);
-/**
+/*
* Return the current height in pixels of the window surface. Returns a
* negative value on error.
*/
int32_t ANativeWindow_getHeight(ANativeWindow* window);
-/**
+/*
* Return the current pixel format of the window surface. Returns a
* negative value on error.
*/
int32_t ANativeWindow_getFormat(ANativeWindow* window);
-/**
+/*
* Change the format and size of the window buffers.
*
* The width and height control the number of pixels in the buffers, not the
@@ -146,5 +124,3 @@
#endif
#endif // ANDROID_NATIVE_WINDOW_H
-
-/** @} */
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 60a36c3..b9e72ef 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
- * @file native_window_jni.h
- */
-
#ifndef ANDROID_NATIVE_WINDOW_JNI_H
#define ANDROID_NATIVE_WINDOW_JNI_H
@@ -47,5 +38,3 @@
#endif
#endif // ANDROID_NATIVE_WINDOW_H
-
-/** @} */
diff --git a/include/android/obb.h b/include/android/obb.h
index 4c6d9d7..65e9b2a 100644
--- a/include/android/obb.h
+++ b/include/android/obb.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Storage
- * @{
- */
-
-/**
- * @file obb.h
- */
#ifndef ANDROID_OBB_H
#define ANDROID_OBB_H
@@ -33,12 +25,9 @@
#endif
struct AObbInfo;
-/** {@link AObbInfo} is an opaque type representing information for obb storage. */
typedef struct AObbInfo AObbInfo;
-/** Flag for an obb file, returned by AObbInfo_getFlags(). */
enum {
- /** overlay */
AOBBINFO_OVERLAY = 0x0001,
};
@@ -72,5 +61,3 @@
#endif
#endif // ANDROID_OBB_H
-
-/** @} */
diff --git a/include/android/rect.h b/include/android/rect.h
index 80741c0..bcd42a9 100644
--- a/include/android/rect.h
+++ b/include/android/rect.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
- * @file rect.h
- */
#ifndef ANDROID_RECT_H
#define ANDROID_RECT_H
@@ -32,24 +24,13 @@
extern "C" {
#endif
-/**
- * {@link ARect} is a struct that represents a rectangular window area.
- *
- * It is used with {@link
- * ANativeActivityCallbacks::onContentRectChanged} event callback and
- * ANativeWindow_lock() function.
- */
typedef struct ARect {
#ifdef __cplusplus
typedef int32_t value_type;
#endif
- /** left position */
int32_t left;
- /** top position */
int32_t top;
- /** left position */
int32_t right;
- /** bottom position */
int32_t bottom;
} ARect;
@@ -58,5 +39,3 @@
#endif
#endif // ANDROID_RECT_H
-
-/** @} */
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 4600dad..1be6232 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Sensor
- * @{
- */
-
-/**
- * @file sensor.h
- */
#ifndef ANDROID_SENSOR_H
#define ANDROID_SENSOR_H
@@ -42,7 +34,7 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
-/**
+/*
* Structures and functions to receive and process sensor events in
* native code.
*
@@ -57,82 +49,37 @@
#endif
-/**
- * Sensor types.
+/*
+ * Sensor types
* (keep in sync with hardware/sensor.h)
*/
+
enum {
- /**
- * {@link ASENSOR_TYPE_ACCELEROMETER}
- * reporting-mode: continuous
- *
- * All values are in SI units (m/s^2) and measure the acceleration of the
- * device minus the force of gravity.
- */
ASENSOR_TYPE_ACCELEROMETER = 1,
- /**
- * {@link ASENSOR_TYPE_MAGNETIC_FIELD}
- * reporting-mode: continuous
- *
- * All values are in micro-Tesla (uT) and measure the geomagnetic
- * field in the X, Y and Z axis.
- */
ASENSOR_TYPE_MAGNETIC_FIELD = 2,
- /**
- * {@link ASENSOR_TYPE_GYROSCOPE}
- * reporting-mode: continuous
- *
- * All values are in radians/second and measure the rate of rotation
- * around the X, Y and Z axis.
- */
ASENSOR_TYPE_GYROSCOPE = 4,
- /**
- * {@link ASENSOR_TYPE_LIGHT}
- * reporting-mode: on-change
- *
- * The light sensor value is returned in SI lux units.
- */
ASENSOR_TYPE_LIGHT = 5,
- /**
- * {@link ASENSOR_TYPE_PROXIMITY}
- * reporting-mode: on-change
- *
- * The proximity sensor which turns the screen off and back on during calls is the
- * wake-up proximity sensor. Implement wake-up proximity sensor before implementing
- * a non wake-up proximity sensor. For the wake-up proximity sensor set the flag
- * SENSOR_FLAG_WAKE_UP.
- * The value corresponds to the distance to the nearest object in centimeters.
- */
ASENSOR_TYPE_PROXIMITY = 8
};
-/**
- * Sensor accuracy measure.
+/*
+ * Sensor accuracy measure
*/
enum {
- /** no contact */
ASENSOR_STATUS_NO_CONTACT = -1,
- /** unreliable */
ASENSOR_STATUS_UNRELIABLE = 0,
- /** low accuracy */
ASENSOR_STATUS_ACCURACY_LOW = 1,
- /** medium accuracy */
ASENSOR_STATUS_ACCURACY_MEDIUM = 2,
- /** high accuracy */
ASENSOR_STATUS_ACCURACY_HIGH = 3
};
-/**
+/*
* Sensor Reporting Modes.
*/
enum {
- /** continuous reporting */
AREPORTING_MODE_CONTINUOUS = 0,
- /** reporting on change */
AREPORTING_MODE_ON_CHANGE = 1,
- /** on shot reporting */
AREPORTING_MODE_ONE_SHOT = 2,
- /** special trigger reporting */
AREPORTING_MODE_SPECIAL_TRIGGER = 3
};
@@ -140,14 +87,14 @@
* A few useful constants
*/
-/** Earth's gravity in m/s^2 */
+/* Earth's gravity in m/s^2 */
#define ASENSOR_STANDARD_GRAVITY (9.80665f)
-/** Maximum magnetic field on Earth's surface in uT */
+/* Maximum magnetic field on Earth's surface in uT */
#define ASENSOR_MAGNETIC_FIELD_EARTH_MAX (60.0f)
-/** Minimum magnetic field on Earth's surface in uT*/
+/* Minimum magnetic field on Earth's surface in uT*/
#define ASENSOR_MAGNETIC_FIELD_EARTH_MIN (30.0f)
-/**
+/*
* A sensor event.
*/
@@ -233,121 +180,67 @@
} ASensorEvent;
struct ASensorManager;
-/**
- * {@link ASensorManager} is an opaque type to manage sensors and
- * events queues.
- *
- * {@link ASensorManager} is a singleton that can be obtained using
- * ASensorManager_getInstance().
- *
- * This file provides a set of functions that uses {@link
- * ASensorManager} to access and list hardware sensors, and
- * create and destroy event queues:
- * - ASensorManager_getSensorList()
- * - ASensorManager_getDefaultSensor()
- * - ASensorManager_getDefaultSensorEx()
- * - ASensorManager_createEventQueue()
- * - ASensorManager_destroyEventQueue()
- */
typedef struct ASensorManager ASensorManager;
-
struct ASensorEventQueue;
-/**
- * {@link ASensorEventQueue} is an opaque type that provides access to
- * {@link ASensorEvent} from hardware sensors.
- *
- * A new {@link ASensorEventQueue} can be obtained using ASensorManager_createEventQueue().
- *
- * This file provides a set of functions to enable and disable
- * sensors, check and get events, and set event rates on a {@link
- * ASensorEventQueue}.
- * - ASensorEventQueue_enableSensor()
- * - ASensorEventQueue_disableSensor()
- * - ASensorEventQueue_hasEvents()
- * - ASensorEventQueue_getEvents()
- * - ASensorEventQueue_setEventRate()
- */
typedef struct ASensorEventQueue ASensorEventQueue;
struct ASensor;
-/**
- * {@link ASensor} is an opaque type that provides information about
- * an hardware sensors.
- *
- * A {@link ASensor} pointer can be obtained using
- * ASensorManager_getDefaultSensor(),
- * ASensorManager_getDefaultSensorEx() or from a {@link ASensorList}.
- *
- * This file provides a set of functions to access properties of a
- * {@link ASensor}:
- * - ASensor_getName()
- * - ASensor_getVendor()
- * - ASensor_getType()
- * - ASensor_getResolution()
- * - ASensor_getMinDelay()
- * - ASensor_getFifoMaxEventCount()
- * - ASensor_getFifoReservedEventCount()
- * - ASensor_getStringType()
- * - ASensor_getReportingMode()
- * - ASensor_isWakeUpSensor()
- */
typedef struct ASensor ASensor;
-/**
- * {@link ASensorRef} is a type for constant pointers to {@link ASensor}.
- *
- * This is used to define entry in {@link ASensorList} arrays.
- */
typedef ASensor const* ASensorRef;
-/**
- * {@link ASensorList} is an array of reference to {@link ASensor}.
- *
- * A {@link ASensorList} can be initialized using ASensorManager_getSensorList().
- */
typedef ASensorRef const* ASensorList;
/*****************************************************************************/
-/**
- * Get a reference to the sensor manager. ASensorManager is a singleton.
+/*
+ * Get a reference to the sensor manager. ASensorManager is a singleton
+ * per package as different packages may have access to different sensors.
+ *
+ * Deprecated: Use ASensorManager_getInstanceForPackage(const char*) instead.
*
* Example:
*
* ASensorManager* sensorManager = ASensorManager_getInstance();
*
*/
-ASensorManager* ASensorManager_getInstance();
+__attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance();
+/*
+ * Get a reference to the sensor manager. ASensorManager is a singleton
+ * per package as different packages may have access to different sensors.
+ *
+ * Example:
+ *
+ * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
+ *
+ */
+ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName);
-/**
+/*
* Returns the list of available sensors.
*/
int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list);
-/**
+/*
* Returns the default sensor for the given type, or NULL if no sensor
* of that type exists.
*/
ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
-/**
+/*
* Returns the default sensor with the given type and wakeUp properties or NULL if no sensor
* of this type and wakeUp properties exists.
*/
ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type,
bool wakeUp);
-/**
+/*
* Creates a new sensor event queue and associate it with a looper.
- *
- * "ident" is a identifier for the events that will be returned when
- * calling ALooper_pollOnce(). The identifier must be >= 0, or
- * ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
*/
ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
ALooper* looper, int ident, ALooper_callbackFunc callback, void* data);
-/**
+/*
* Destroys the event queue and free all resources associated to it.
*/
int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue);
@@ -355,17 +248,17 @@
/*****************************************************************************/
-/**
+/*
* Enable the selected sensor. Returns a negative error code on failure.
*/
int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor);
-/**
+/*
* Disable the selected sensor. Returns a negative error code on failure.
*/
int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor);
-/**
+/*
* Sets the delivery rate of events in microseconds for the given sensor.
* Note that this is a hint only, generally event will arrive at a higher
* rate. It is an error to set a rate inferior to the value returned by
@@ -374,14 +267,14 @@
*/
int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec);
-/**
+/*
* Returns true if there are one or more events available in the
* sensor queue. Returns 1 if the queue has events; 0 if
* it does not have events; and a negative value if there is an error.
*/
int ASensorEventQueue_hasEvents(ASensorEventQueue* queue);
-/**
+/*
* Returns the next available events from the queue. Returns a negative
* value if no events are available or an error has occurred, otherwise
* the number of events returned.
@@ -400,55 +293,55 @@
/*****************************************************************************/
-/**
+/*
* Returns this sensor's name (non localized)
*/
const char* ASensor_getName(ASensor const* sensor);
-/**
+/*
* Returns this sensor's vendor's name (non localized)
*/
const char* ASensor_getVendor(ASensor const* sensor);
-/**
+/*
* Return this sensor's type
*/
int ASensor_getType(ASensor const* sensor);
-/**
+/*
* Returns this sensors's resolution
*/
float ASensor_getResolution(ASensor const* sensor);
-/**
+/*
* Returns the minimum delay allowed between events in microseconds.
* A value of zero means that this sensor doesn't report events at a
* constant rate, but rather only when a new data is available.
*/
int ASensor_getMinDelay(ASensor const* sensor);
-/**
+/*
* Returns the maximum size of batches for this sensor. Batches will often be
* smaller, as the hardware fifo might be used for other sensors.
*/
int ASensor_getFifoMaxEventCount(ASensor const* sensor);
-/**
+/*
* Returns the hardware batch fifo size reserved to this sensor.
*/
int ASensor_getFifoReservedEventCount(ASensor const* sensor);
-/**
+/*
* Returns this sensor's string type.
*/
const char* ASensor_getStringType(ASensor const* sensor);
-/**
+/*
* Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants.
*/
int ASensor_getReportingMode(ASensor const* sensor);
-/**
+/*
* Returns true if this is a wake up sensor, false otherwise.
*/
bool ASensor_isWakeUpSensor(ASensor const* sensor);
@@ -458,5 +351,3 @@
#endif
#endif // ANDROID_SENSOR_H
-
-/** @} */
diff --git a/include/android/storage_manager.h b/include/android/storage_manager.h
index 7f2ee08..bad2491 100644
--- a/include/android/storage_manager.h
+++ b/include/android/storage_manager.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup Storage
- * @{
- */
-
-/**
- * @file storage_manager.h
- */
#ifndef ANDROID_STORAGE_MANAGER_H
#define ANDROID_STORAGE_MANAGER_H
@@ -33,62 +25,55 @@
#endif
struct AStorageManager;
-/**
- * {@link AStorageManager} manages application OBB storage, a pointer
- * can be obtained with AStorageManager_new().
- */
typedef struct AStorageManager AStorageManager;
-/**
- * The different states of a OBB storage passed to AStorageManager_obbCallbackFunc().
- */
enum {
- /**
+ /*
* The OBB container is now mounted and ready for use. Can be returned
* as the status for callbacks made during asynchronous OBB actions.
*/
AOBB_STATE_MOUNTED = 1,
- /**
+ /*
* The OBB container is now unmounted and not usable. Can be returned
* as the status for callbacks made during asynchronous OBB actions.
*/
AOBB_STATE_UNMOUNTED = 2,
- /**
+ /*
* There was an internal system error encountered while trying to
* mount the OBB. Can be returned as the status for callbacks made
* during asynchronous OBB actions.
*/
AOBB_STATE_ERROR_INTERNAL = 20,
- /**
+ /*
* The OBB could not be mounted by the system. Can be returned as the
* status for callbacks made during asynchronous OBB actions.
*/
AOBB_STATE_ERROR_COULD_NOT_MOUNT = 21,
- /**
+ /*
* The OBB could not be unmounted. This most likely indicates that a
* file is in use on the OBB. Can be returned as the status for
* callbacks made during asynchronous OBB actions.
*/
AOBB_STATE_ERROR_COULD_NOT_UNMOUNT = 22,
- /**
+ /*
* A call was made to unmount the OBB when it was not mounted. Can be
* returned as the status for callbacks made during asynchronous OBB
* actions.
*/
AOBB_STATE_ERROR_NOT_MOUNTED = 23,
- /**
+ /*
* The OBB has already been mounted. Can be returned as the status for
* callbacks made during asynchronous OBB actions.
*/
AOBB_STATE_ERROR_ALREADY_MOUNTED = 24,
- /**
+ /*
* The current application does not have permission to use this OBB.
* This could be because the OBB indicates it's owned by a different
* package. Can be returned as the status for callbacks made during
@@ -109,16 +94,6 @@
/**
* Callback function for asynchronous calls made on OBB files.
- *
- * "state" is one of the following constants:
- * - {@link AOBB_STATE_MOUNTED}
- * - {@link AOBB_STATE_UNMOUNTED}
- * - {@link AOBB_STATE_ERROR_INTERNAL}
- * - {@link AOBB_STATE_ERROR_COULD_NOT_MOUNT}
- * - {@link AOBB_STATE_ERROR_COULD_NOT_UNMOUNT}
- * - {@link AOBB_STATE_ERROR_NOT_MOUNTED}
- * - {@link AOBB_STATE_ERROR_ALREADY_MOUNTED}
- * - {@link AOBB_STATE_ERROR_PERMISSION_DENIED}
*/
typedef void (*AStorageManager_obbCallbackFunc)(const char* filename, const int32_t state, void* data);
@@ -150,5 +125,3 @@
#endif
#endif // ANDROID_STORAGE_MANAGER_H
-
-/** @} */
diff --git a/include/android/trace.h b/include/android/trace.h
new file mode 100644
index 0000000..e42e334
--- /dev/null
+++ b/include/android/trace.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+
+#ifndef ANDROID_NATIVE_TRACE_H
+#define ANDROID_NATIVE_TRACE_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary
+ * when tracing is enabled.
+ */
+bool ATrace_isEnabled();
+
+/**
+ * Writes a tracing message to indicate that the given section of code has begun. This call must be
+ * followed by a corresponding call to endSection() on the same thread.
+ *
+ * Note: At this time the vertical bar character '|' and newline character '\n' are used internally
+ * by the tracing mechanism. If sectionName contains these characters they will be replaced with a
+ * space character in the trace.
+ */
+void ATrace_beginSection(const char* sectionName);
+
+/**
+ * Writes a tracing message to indicate that a given section of code has ended. This call must be
+ * preceeded by a corresponding call to beginSection(char*) on the same thread. Calling this method
+ * will mark the end of the most recently begun section of code, so care must be taken to ensure
+ * that beginSection / endSection pairs are properly nested and called from the same thread.
+ */
+void ATrace_endSection();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_NATIVE_TRACE_H
diff --git a/include/android/window.h b/include/android/window.h
index 436bf3a..2ab192b 100644
--- a/include/android/window.h
+++ b/include/android/window.h
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
- * @file window.h
- */
#ifndef ANDROID_WINDOW_H
#define ANDROID_WINDOW_H
@@ -34,184 +26,28 @@
* Window flags, as per the Java API at android.view.WindowManager.LayoutParams.
*/
enum {
- /**
- * As long as this window is visible to the user, allow the lock
- * screen to activate while the screen is on. This can be used
- * independently, or in combination with {@link
- * AWINDOW_FLAG_KEEP_SCREEN_ON} and/or {@link
- * AWINDOW_FLAG_SHOW_WHEN_LOCKED}
- */
AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
- /** Everything behind this window will be dimmed. */
AWINDOW_FLAG_DIM_BEHIND = 0x00000002,
- /**
- * Blur everything behind this window.
- * @deprecated Blurring is no longer supported.
- */
AWINDOW_FLAG_BLUR_BEHIND = 0x00000004,
- /**
- * This window won't ever get key input focus, so the
- * user can not send key or other button events to it. Those will
- * instead go to whatever focusable window is behind it. This flag
- * will also enable {@link AWINDOW_FLAG_NOT_TOUCH_MODAL} whether or not that
- * is explicitly set.
- *
- * Setting this flag also implies that the window will not need to
- * interact with
- * a soft input method, so it will be Z-ordered and positioned
- * independently of any active input method (typically this means it
- * gets Z-ordered on top of the input method, so it can use the full
- * screen for its content and cover the input method if needed. You
- * can use {@link AWINDOW_FLAG_ALT_FOCUSABLE_IM} to modify this behavior.
- */
AWINDOW_FLAG_NOT_FOCUSABLE = 0x00000008,
- /** this window can never receive touch events. */
AWINDOW_FLAG_NOT_TOUCHABLE = 0x00000010,
- /**
- * Even when this window is focusable (its
- * {@link AWINDOW_FLAG_NOT_FOCUSABLE} is not set), allow any pointer events
- * outside of the window to be sent to the windows behind it. Otherwise
- * it will consume all pointer events itself, regardless of whether they
- * are inside of the window.
- */
AWINDOW_FLAG_NOT_TOUCH_MODAL = 0x00000020,
- /**
- * When set, if the device is asleep when the touch
- * screen is pressed, you will receive this first touch event. Usually
- * the first touch event is consumed by the system since the user can
- * not see what they are pressing on.
- *
- * @deprecated This flag has no effect.
- */
AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
- /**
- * As long as this window is visible to the user, keep
- * the device's screen turned on and bright.
- */
AWINDOW_FLAG_KEEP_SCREEN_ON = 0x00000080,
- /**
- * Place the window within the entire screen, ignoring
- * decorations around the border (such as the status bar). The
- * window must correctly position its contents to take the screen
- * decoration into account.
- */
AWINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100,
- /** allow window to extend outside of the screen. */
AWINDOW_FLAG_LAYOUT_NO_LIMITS = 0x00000200,
- /**
- * Hide all screen decorations (such as the status
- * bar) while this window is displayed. This allows the window to
- * use the entire display space for itself -- the status bar will
- * be hidden when an app window with this flag set is on the top
- * layer. A fullscreen window will ignore a value of {@link
- * AWINDOW_SOFT_INPUT_ADJUST_RESIZE}; the window will stay
- * fullscreen and will not resize.
- */
AWINDOW_FLAG_FULLSCREEN = 0x00000400,
- /**
- * Override {@link AWINDOW_FLAG_FULLSCREEN} and force the
- * screen decorations (such as the status bar) to be shown.
- */
AWINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800,
- /**
- * Turn on dithering when compositing this window to
- * the screen.
- * @deprecated This flag is no longer used.
- */
AWINDOW_FLAG_DITHER = 0x00001000,
- /**
- * Treat the content of the window as secure, preventing
- * it from appearing in screenshots or from being viewed on non-secure
- * displays.
- */
AWINDOW_FLAG_SECURE = 0x00002000,
- /**
- * A special mode where the layout parameters are used
- * to perform scaling of the surface when it is composited to the
- * screen.
- */
AWINDOW_FLAG_SCALED = 0x00004000,
- /**
- * Intended for windows that will often be used when the user is
- * holding the screen against their face, it will aggressively
- * filter the event stream to prevent unintended presses in this
- * situation that may not be desired for a particular window, when
- * such an event stream is detected, the application will receive
- * a {@link AMOTION_EVENT_ACTION_CANCEL} to indicate this so
- * applications can handle this accordingly by taking no action on
- * the event until the finger is released.
- */
AWINDOW_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000,
- /**
- * A special option only for use in combination with
- * {@link AWINDOW_FLAG_LAYOUT_IN_SCREEN}. When requesting layout in the
- * screen your window may appear on top of or behind screen decorations
- * such as the status bar. By also including this flag, the window
- * manager will report the inset rectangle needed to ensure your
- * content is not covered by screen decorations.
- */
AWINDOW_FLAG_LAYOUT_INSET_DECOR = 0x00010000,
- /**
- * Invert the state of {@link AWINDOW_FLAG_NOT_FOCUSABLE} with
- * respect to how this window interacts with the current method.
- * That is, if FLAG_NOT_FOCUSABLE is set and this flag is set,
- * then the window will behave as if it needs to interact with the
- * input method and thus be placed behind/away from it; if {@link
- * AWINDOW_FLAG_NOT_FOCUSABLE} is not set and this flag is set,
- * then the window will behave as if it doesn't need to interact
- * with the input method and can be placed to use more space and
- * cover the input method.
- */
AWINDOW_FLAG_ALT_FOCUSABLE_IM = 0x00020000,
- /**
- * If you have set {@link AWINDOW_FLAG_NOT_TOUCH_MODAL}, you
- * can set this flag to receive a single special MotionEvent with
- * the action
- * {@link AMOTION_EVENT_ACTION_OUTSIDE} for
- * touches that occur outside of your window. Note that you will not
- * receive the full down/move/up gesture, only the location of the
- * first down as an {@link AMOTION_EVENT_ACTION_OUTSIDE}.
- */
AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
- /**
- * Special flag to let windows be shown when the screen
- * is locked. This will let application windows take precedence over
- * key guard or any other lock screens. Can be used with
- * {@link AWINDOW_FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
- * directly before showing the key guard window. Can be used with
- * {@link AWINDOW_FLAG_DISMISS_KEYGUARD} to automatically fully dismisss
- * non-secure keyguards. This flag only applies to the top-most
- * full-screen window.
- */
AWINDOW_FLAG_SHOW_WHEN_LOCKED = 0x00080000,
- /**
- * Ask that the system wallpaper be shown behind
- * your window. The window surface must be translucent to be able
- * to actually see the wallpaper behind it; this flag just ensures
- * that the wallpaper surface will be there if this window actually
- * has translucent regions.
- */
AWINDOW_FLAG_SHOW_WALLPAPER = 0x00100000,
- /**
- * When set as a window is being added or made
- * visible, once the window has been shown then the system will
- * poke the power manager's user activity (as if the user had woken
- * up the device) to turn the screen on.
- */
AWINDOW_FLAG_TURN_SCREEN_ON = 0x00200000,
- /**
- * When set the window will cause the keyguard to
- * be dismissed, only if it is not a secure lock keyguard. Because such
- * a keyguard is not needed for security, it will never re-appear if
- * the user navigates to another window (in contrast to
- * {@link AWINDOW_FLAG_SHOW_WHEN_LOCKED}, which will only temporarily
- * hide both secure and non-secure keyguards but ensure they reappear
- * when the user moves to another UI that doesn't hide them).
- * If the keyguard is currently active and is secure (requires an
- * unlock pattern) than the user will still need to confirm it before
- * seeing this window, unless {@link AWINDOW_FLAG_SHOW_WHEN_LOCKED} has
- * also been set.
- */
AWINDOW_FLAG_DISMISS_KEYGUARD = 0x00400000,
};
@@ -220,5 +56,3 @@
#endif
#endif // ANDROID_WINDOW_H
-
-/** @} */
diff --git a/include/binder/AppOpsManager.h b/include/binder/AppOpsManager.h
index 256cb94..042927c 100644
--- a/include/binder/AppOpsManager.h
+++ b/include/binder/AppOpsManager.h
@@ -63,7 +63,35 @@
OP_ACCESS_NOTIFICATIONS = 25,
OP_CAMERA = 26,
OP_RECORD_AUDIO = 27,
- OP_PLAY_AUDIO = 28
+ OP_PLAY_AUDIO = 28,
+ OP_READ_CLIPBOARD = 29,
+ OP_WRITE_CLIPBOARD = 30,
+ OP_TAKE_MEDIA_BUTTONS = 31,
+ OP_TAKE_AUDIO_FOCUS = 32,
+ OP_AUDIO_MASTER_VOLUME = 33,
+ OP_AUDIO_VOICE_VOLUME = 34,
+ OP_AUDIO_RING_VOLUME = 35,
+ OP_AUDIO_MEDIA_VOLUME = 36,
+ OP_AUDIO_ALARM_VOLUME = 37,
+ OP_AUDIO_NOTIFICATION_VOLUME = 38,
+ OP_AUDIO_BLUETOOTH_VOLUME = 39,
+ OP_WAKE_LOCK = 40,
+ OP_MONITOR_LOCATION = 41,
+ OP_MONITOR_HIGH_POWER_LOCATION = 42,
+ OP_GET_USAGE_STATS = 43,
+ OP_MUTE_MICROPHONE = 44,
+ OP_TOAST_WINDOW = 45,
+ OP_PROJECT_MEDIA = 46,
+ OP_ACTIVATE_VPN = 47,
+ OP_WRITE_WALLPAPER = 48,
+ OP_ASSIST_STRUCTURE = 49,
+ OP_ASSIST_SCREENSHOT = 50,
+ OP_READ_PHONE_STATE = 51,
+ OP_ADD_VOICEMAIL = 52,
+ OP_USE_SIP = 53,
+ OP_PROCESS_OUTGOING_CALLS = 54,
+ OP_USE_FINGERPRINT = 55,
+ OP_BODY_SENSORS = 56
};
AppOpsManager();
@@ -75,6 +103,7 @@
void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback);
void stopWatchingMode(const sp<IAppOpsCallback>& callback);
+ int32_t permissionToOpCode(const String16& permission);
private:
Mutex mLock;
diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h
index 193e9cc..cd81efa 100644
--- a/include/binder/IAppOpsService.h
+++ b/include/binder/IAppOpsService.h
@@ -40,6 +40,7 @@
const sp<IAppOpsCallback>& callback) = 0;
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) = 0;
+ virtual int32_t permissionToOpCode(const String16& permission) = 0;
enum {
CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -49,6 +50,7 @@
START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4,
STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5,
GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
+ PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
};
enum {
diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h
index 7ddac57..5f38186 100644
--- a/include/binder/IBatteryStats.h
+++ b/include/binder/IBatteryStats.h
@@ -36,6 +36,12 @@
virtual void noteStopAudio(int uid) = 0;
virtual void noteResetVideo() = 0;
virtual void noteResetAudio() = 0;
+ virtual void noteFlashlightOn(int uid) = 0;
+ virtual void noteFlashlightOff(int uid) = 0;
+ virtual void noteStartCamera(int uid) = 0;
+ virtual void noteStopCamera(int uid) = 0;
+ virtual void noteResetCamera() = 0;
+ virtual void noteResetFlashlight() = 0;
enum {
NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -46,6 +52,12 @@
NOTE_STOP_AUDIO_TRANSACTION,
NOTE_RESET_VIDEO_TRANSACTION,
NOTE_RESET_AUDIO_TRANSACTION,
+ NOTE_FLASHLIGHT_ON_TRANSACTION,
+ NOTE_FLASHLIGHT_OFF_TRANSACTION,
+ NOTE_START_CAMERA_TRANSACTION,
+ NOTE_STOP_CAMERA_TRANSACTION,
+ NOTE_RESET_CAMERA_TRANSACTION,
+ NOTE_RESET_FLASHLIGHT_TRANSACTION
};
};
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 60c2242..1853cff 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -76,14 +76,18 @@
BpBinder* proxy);
static void shutdown();
-
+
// Call this to disable switching threads to background scheduling when
// receiving incoming IPC calls. This is specifically here for the
// Android system process, since it expects to have background apps calling
// in to it but doesn't want to acquire locks in its services while in
// the background.
static void disableBackgroundScheduling(bool disable);
-
+
+ // Call blocks until the number of executing binder threads is less than
+ // the maximum number of binder threads threads allowed for this process.
+ void blockUntilThreadAvailable();
+
private:
IPCThreadState();
~IPCThreadState();
@@ -101,9 +105,9 @@
status_t getAndExecuteCommand();
status_t executeCommand(int32_t command);
void processPendingDerefs();
-
+
void clearCaller();
-
+
static void threadDestructor(void *st);
static void freeBuffer(Parcel* parcel,
const uint8_t* data, size_t dataSize,
@@ -114,7 +118,7 @@
const pid_t mMyThreadId;
Vector<BBinder*> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
+
Parcel mIn;
Parcel mOut;
status_t mLastError;
diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h
index f9d371b..4e5fb34 100644
--- a/include/binder/IPermissionController.h
+++ b/include/binder/IPermissionController.h
@@ -19,6 +19,7 @@
#define ANDROID_IPERMISSION_CONTROLLER_H
#include <binder/IInterface.h>
+#include <stdlib.h>
namespace android {
@@ -29,11 +30,16 @@
public:
DECLARE_META_INTERFACE(PermissionController);
- virtual bool checkPermission(const String16& permission,
- int32_t pid, int32_t uid) = 0;
-
+ virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
+
+ virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0;
+
+ virtual bool isRuntimePermission(const String16& permission) = 0;
+
enum {
- CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+ CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
+ IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
};
};
diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h
new file mode 100644
index 0000000..dc62f45
--- /dev/null
+++ b/include/binder/IProcessInfoService.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef ANDROID_I_PROCESS_INFO_SERVICE_H
+#define ANDROID_I_PROCESS_INFO_SERVICE_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IProcessInfoService : public IInterface {
+public:
+ DECLARE_META_INTERFACE(ProcessInfoService);
+
+ virtual status_t getProcessStatesFromPids( size_t length,
+ /*in*/ int32_t* pids,
+ /*out*/ int32_t* states) = 0;
+
+ enum {
+ GET_PROCESS_STATES_FROM_PIDS = IBinder::FIRST_CALL_TRANSACTION,
+ };
+};
+
+// ----------------------------------------------------------------------
+
+class BnProcessInfoService : public BnInterface<IProcessInfoService> {
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 0ba3abe..3ada1e9 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -60,6 +60,7 @@
status_t appendFrom(const Parcel *parcel,
size_t start, size_t len);
+ bool allowFds() const;
bool pushAllowFds(bool allowFds);
void restoreAllowFds(bool lastValue);
@@ -130,16 +131,18 @@
// will be closed once the parcel is destroyed.
status_t writeDupFileDescriptor(int fd);
- // Writes a raw fd and optional comm channel fd to the parcel as a ParcelFileDescriptor.
- // A dup's of the fds are made, which will be closed once the parcel is destroyed.
- // Null values are passed as -1.
- status_t writeParcelFileDescriptor(int fd, int commChannel = -1);
-
// Writes a blob to the parcel.
// If the blob is small, then it is stored in-place, otherwise it is
- // transferred by way of an anonymous shared memory region.
+ // transferred by way of an anonymous shared memory region. Prefer sending
+ // immutable blobs if possible since they may be subsequently transferred between
+ // processes without further copying whereas mutable blobs always need to be copied.
// The caller should call release() on the blob after writing its contents.
- status_t writeBlob(size_t len, WritableBlob* outBlob);
+ status_t writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob);
+
+ // Write an existing immutable blob file descriptor to the parcel.
+ // This allows the client to send the same blob to multiple processes
+ // as long as it keeps a dup of the blob file descriptor handy for later.
+ status_t writeDupImmutableBlobFileDescriptor(int fd);
status_t writeObject(const flat_binder_object& val, bool nullMetaData);
@@ -198,11 +201,6 @@
// in the parcel, which you do not own -- use dup() to get your own copy.
int readFileDescriptor() const;
- // Reads a ParcelFileDescriptor from the parcel. Returns the raw fd as
- // the result, and the optional comm channel fd in outCommChannel.
- // Null values are returned as -1.
- int readParcelFileDescriptor(int& outCommChannel) const;
-
// Reads a blob from the parcel.
// The caller should call release() on the blob after reading its contents.
status_t readBlob(size_t len, ReadableBlob* outBlob) const;
@@ -280,16 +278,19 @@
Blob();
~Blob();
+ void clear();
void release();
inline size_t size() const { return mSize; }
+ inline int fd() const { return mFd; };
+ inline bool isMutable() const { return mMutable; }
protected:
- void init(bool mapped, void* data, size_t size);
- void clear();
+ void init(int fd, void* data, size_t size, bool isMutable);
- bool mMapped;
+ int mFd; // owned by parcel so not closed when released
void* mData;
size_t mSize;
+ bool mMutable;
};
class FlattenableHelperInterface {
@@ -330,6 +331,7 @@
friend class Parcel;
public:
inline const void* data() const { return mData; }
+ inline void* mutableData() { return isMutable() ? mData : NULL; }
};
class WritableBlob : public Blob {
@@ -337,6 +339,12 @@
public:
inline void* data() { return mData; }
};
+
+private:
+ size_t mBlobAshmemSize;
+
+public:
+ size_t getBlobAshmemSize() const;
};
// ---------------------------------------------------------------------------
diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h
new file mode 100644
index 0000000..c5ead20
--- /dev/null
+++ b/include/binder/ProcessInfoService.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef ANDROID_PROCESS_INFO_SERVICE_H
+#define ANDROID_PROCESS_INFO_SERVICE_H
+
+#include <binder/IProcessInfoService.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+#include <sys/types.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class ProcessInfoService : public Singleton<ProcessInfoService> {
+
+ friend class Singleton<ProcessInfoService>;
+ sp<IProcessInfoService> mProcessInfoService;
+ Mutex mProcessInfoLock;
+
+ ProcessInfoService();
+
+ status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states);
+ void updateBinderLocked();
+
+ static const int BINDER_ATTEMPT_LIMIT = 5;
+
+public:
+
+ /**
+ * For each PID in the given "pids" input array, write the current process state
+ * for that process into the "states" output array, or
+ * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID
+ * exists.
+ *
+ * Returns NO_ERROR if this operation was successful, or a negative error code otherwise.
+ */
+ static status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
+ /*out*/ int32_t* states) {
+ return ProcessInfoService::getInstance().getProcessStatesImpl(length, /*in*/ pids,
+ /*out*/ states);
+ }
+
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_PROCESS_INFO_SERVICE_H
+
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 3bc978d..f9edc2a 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -24,6 +24,8 @@
#include <utils/threads.h>
+#include <pthread.h>
+
// ---------------------------------------------------------------------------
namespace android {
@@ -71,25 +73,33 @@
ProcessState(const ProcessState& o);
ProcessState& operator=(const ProcessState& o);
String8 makeBinderThreadName();
-
+
struct handle_entry {
IBinder* binder;
RefBase::weakref_type* refs;
};
-
+
handle_entry* lookupHandleLocked(int32_t handle);
int mDriverFD;
void* mVMStart;
-
+
+ // Protects thread count variable below.
+ pthread_mutex_t mThreadCountLock;
+ pthread_cond_t mThreadCountDecrement;
+ // Number of binder threads current executing a command.
+ size_t mExecutingThreadsCount;
+ // Maximum number for binder threads allowed for this process.
+ size_t mMaxThreads;
+
mutable Mutex mLock; // protects everything below.
-
+
Vector<handle_entry>mHandleToObject;
bool mManagesContexts;
context_check_func mBinderContextCheckFunc;
void* mBinderContextUserData;
-
+
KeyedVector<String16, sp<IBinder> >
mContexts;
diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h
index 9c8afc5..3dca2a3 100644
--- a/include/gui/ISensorServer.h
+++ b/include/gui/ISensorServer.h
@@ -30,14 +30,17 @@
class Sensor;
class ISensorEventConnection;
+class String8;
class ISensorServer : public IInterface
{
public:
DECLARE_META_INTERFACE(SensorServer);
- virtual Vector<Sensor> getSensorList() = 0;
- virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;
+ virtual Vector<Sensor> getSensorList(const String16& opPackageName) = 0;
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+ int mode, const String16& opPackageName) = 0;
+ virtual int32_t isDataInjectionEnabled() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 27a215e..8142be6 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -71,6 +71,8 @@
uint32_t getFifoMaxEventCount() const;
const String8& getStringType() const;
const String8& getRequiredPermission() const;
+ bool isRequiredPermissionRuntime() const;
+ int32_t getRequiredAppOp() const;
int32_t getMaxDelay() const;
uint32_t getFlags() const;
bool isWakeUpSensor() const;
@@ -97,6 +99,8 @@
uint32_t mFifoMaxEventCount;
String8 mStringType;
String8 mRequiredPermission;
+ bool mRequiredPermissionRuntime = false;
+ int32_t mRequiredAppOp;
int32_t mMaxDelay;
uint32_t mFlags;
static void flattenString8(void*& buffer, size_t& size, const String8& string8);
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index 02b3d38..e5b9fc5 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
+#include <utils/String16.h>
#include <gui/BitTube.h>
@@ -52,7 +53,7 @@
enum { MAX_RECEIVE_BUFFER_EVENT_COUNT = 256 };
- SensorEventQueue(const sp<ISensorEventConnection>& connection);
+ SensorEventQueue(const sp<ISensorEventConnection>& connection);
virtual ~SensorEventQueue();
virtual void onFirstRef();
@@ -77,6 +78,8 @@
status_t flush() const;
// Send an ack for every wake_up sensor event that is set to WAKE_UP_SENSOR_EVENT_NEEDS_ACK.
void sendAck(const ASensorEvent* events, int count);
+
+ status_t injectSensorEvent(const ASensorEvent& event);
private:
sp<Looper> getLooper() const;
sp<ISensorEventConnection> mSensorEventConnection;
diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h
index 3176462..3796067 100644
--- a/include/gui/SensorManager.h
+++ b/include/gui/SensorManager.h
@@ -17,15 +17,20 @@
#ifndef ANDROID_GUI_SENSOR_MANAGER_H
#define ANDROID_GUI_SENSOR_MANAGER_H
+#include <map>
+
#include <stdint.h>
#include <sys/types.h>
#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Singleton.h>
#include <utils/Vector.h>
+#include <utils/String8.h>
#include <gui/SensorEventQueue.h>
@@ -40,20 +45,69 @@
class ISensorServer;
class Sensor;
class SensorEventQueue;
-
// ----------------------------------------------------------------------------
class SensorManager :
- public ASensorManager,
- public Singleton<SensorManager>
+ public ASensorManager
{
public:
- SensorManager();
+ static SensorManager& getInstanceForPackage(const String16& packageName) {
+ Mutex::Autolock _l(sLock);
+
+ SensorManager* sensorManager;
+ std::map<String16, SensorManager*>::iterator iterator =
+ sPackageInstances.find(packageName);
+
+ if (iterator != sPackageInstances.end()) {
+ sensorManager = iterator->second;
+ } else {
+ String16 opPackageName = packageName;
+
+ // It is possible that the calling code has no access to the package name.
+ // In this case we will get the packages for the calling UID and pick the
+ // first one for attributing the app op. This will work correctly for
+ // runtime permissions as for legacy apps we will toggle the app op for
+ // all packages in the UID. The caveat is that the operation may be attributed
+ // to the wrong package and stats based on app ops may be slightly off.
+ if (opPackageName.size() <= 0) {
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+ if (binder != 0) {
+ const uid_t uid = IPCThreadState::self()->getCallingUid();
+ Vector<String16> packages;
+ interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
+ if (!packages.isEmpty()) {
+ opPackageName = packages[0];
+ } else {
+ ALOGE("No packages for calling UID");
+ }
+ } else {
+ ALOGE("Cannot get permission service");
+ }
+ }
+
+ sensorManager = new SensorManager(opPackageName);
+
+ // If we had no package name, we looked it up from the UID and the sensor
+ // manager instance we created should also be mapped to the empty package
+ // name, to avoid looking up the packages for a UID and get the same result.
+ if (packageName.size() <= 0) {
+ sPackageInstances.insert(std::make_pair(String16(), sensorManager));
+ }
+
+ // Stash the per package sensor manager.
+ sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
+ }
+
+ return *sensorManager;
+ }
+
+ SensorManager(const String16& opPackageName);
~SensorManager();
ssize_t getSensorList(Sensor const* const** list) const;
Sensor const* getDefaultSensor(int type);
- sp<SensorEventQueue> createEventQueue();
+ sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0);
+ bool isDataInjectionEnabled();
private:
// DeathRecipient interface
@@ -62,11 +116,15 @@
status_t assertStateLocked() const;
private:
+ static Mutex sLock;
+ static std::map<String16, SensorManager*> sPackageInstances;
+
mutable Mutex mLock;
mutable sp<ISensorServer> mSensorServer;
mutable Sensor const** mSensorList;
mutable Vector<Sensor> mSensors;
mutable sp<IBinder::DeathRecipient> mDeathObserver;
+ const String16 mOpPackageName;
};
// ----------------------------------------------------------------------------
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
new file mode 100644
index 0000000..629310f
--- /dev/null
+++ b/include/input/IInputFlinger.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef _LIBINPUT_IINPUT_FLINGER_H
+#define _LIBINPUT_IINPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+/*
+ * This class defines the Binder IPC interface for accessing various
+ * InputFlinger features.
+ */
+class IInputFlinger : public IInterface {
+public:
+ DECLARE_META_INTERFACE(InputFlinger);
+};
+
+
+/**
+ * Binder implementation.
+ */
+class BnInputFlinger : public BnInterface<IInputFlinger> {
+public:
+ enum {
+ DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ };
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_IINPUT_FLINGER_H
diff --git a/include/input/Input.h b/include/input/Input.h
index 428fb44..093219a 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -149,10 +149,22 @@
* NOTE: If you want a flag to be able to set in a keylayout file, then you must add it to
* InputEventLabels.h as well. */
+ // Indicates that the event should wake the device.
POLICY_FLAG_WAKE = 0x00000001,
+
+ // Indicates that the key is virtual, such as a capacitive button, and should
+ // generate haptic feedback. Virtual keys may be suppressed for some time
+ // after a recent touch to prevent accidental activation of virtual keys adjacent
+ // to the touch screen during an edge swipe.
POLICY_FLAG_VIRTUAL = 0x00000002,
+
+ // Indicates that the key is the special function modifier.
POLICY_FLAG_FUNCTION = 0x00000004,
+ // Indicates that the key represents a special gesture that has been detected by
+ // the touch firmware or driver. Causes touch events from the same device to be canceled.
+ POLICY_FLAG_GESTURE = 0x00000008,
+
POLICY_FLAG_RAW_MASK = 0x0000ffff,
/* These flags are set by the input dispatcher. */
@@ -367,6 +379,12 @@
inline int32_t getButtonState() const { return mButtonState; }
+ inline int32_t setButtonState(int32_t buttonState) { mButtonState = buttonState; }
+
+ inline int32_t getActionButton() const { return mActionButton; }
+
+ inline void setActionButton(int32_t button) { mActionButton = button; }
+
inline float getXOffset() const { return mXOffset; }
inline float getYOffset() const { return mYOffset; }
@@ -520,6 +538,7 @@
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t actionButton,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
@@ -572,6 +591,7 @@
protected:
int32_t mAction;
+ int32_t mActionButton;
int32_t mFlags;
int32_t mEdgeFlags;
int32_t mMetaState;
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index adf9fb9..1ea69d3 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -73,7 +73,8 @@
};
void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal);
+ const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+ bool hasMic);
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
@@ -84,6 +85,7 @@
return mAlias.isEmpty() ? mIdentifier.name : mAlias;
}
inline bool isExternal() const { return mIsExternal; }
+ inline bool hasMic() const { return mHasMic; }
inline uint32_t getSources() const { return mSources; }
const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
@@ -121,6 +123,7 @@
InputDeviceIdentifier mIdentifier;
String8 mAlias;
bool mIsExternal;
+ bool mHasMic;
uint32_t mSources;
int32_t mKeyboardType;
sp<KeyCharacterMap> mKeyCharacterMap;
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index df50237..a7a9329 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -299,6 +299,14 @@
DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU),
DEFINE_KEYCODE(TV_TIMER_PROGRAMMING),
DEFINE_KEYCODE(HELP),
+ DEFINE_KEYCODE(NAVIGATE_PREVIOUS),
+ DEFINE_KEYCODE(NAVIGATE_NEXT),
+ DEFINE_KEYCODE(NAVIGATE_IN),
+ DEFINE_KEYCODE(NAVIGATE_OUT),
+ DEFINE_KEYCODE(MEDIA_SKIP_FORWARD),
+ DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD),
+ DEFINE_KEYCODE(MEDIA_STEP_FORWARD),
+ DEFINE_KEYCODE(MEDIA_STEP_BACKWARD),
{ NULL, 0 }
};
@@ -376,6 +384,7 @@
static const InputEventLabel FLAGS[] = {
DEFINE_FLAG(VIRTUAL),
DEFINE_FLAG(FUNCTION),
+ DEFINE_FLAG(GESTURE),
{ NULL, 0 }
};
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index e7e383b..f31bcea 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -84,6 +84,7 @@
int32_t deviceId;
int32_t source;
int32_t action;
+ int32_t actionButton;
int32_t flags;
int32_t metaState;
int32_t buttonState;
@@ -95,7 +96,7 @@
float yPrecision;
uint32_t pointerCount;
// Note that PointerCoords requires 8 byte alignment.
- struct Pointer{
+ struct Pointer {
PointerProperties properties;
PointerCoords coords;
} pointers[MAX_POINTERS];
@@ -232,6 +233,7 @@
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t actionButton,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h
index 49939fd..272881b 100644
--- a/include/media/drm/DrmAPI.h
+++ b/include/media/drm/DrmAPI.h
@@ -80,7 +80,10 @@
kDrmPluginEventProvisionRequired = 1,
kDrmPluginEventKeyNeeded,
kDrmPluginEventKeyExpired,
- kDrmPluginEventVendorDefined
+ kDrmPluginEventVendorDefined,
+ kDrmPluginEventSessionReclaimed,
+ kDrmPluginEventExpirationUpdate,
+ kDrmPluginEventKeysChange,
};
// Drm keys can be for offline content or for online streaming.
@@ -93,6 +96,33 @@
kKeyType_Release
};
+ // Enumerate KeyRequestTypes to allow an app to determine the
+ // type of a key request returned from getKeyRequest.
+ enum KeyRequestType {
+ kKeyRequestType_Unknown,
+ kKeyRequestType_Initial,
+ kKeyRequestType_Renewal,
+ kKeyRequestType_Release
+ };
+
+ // Enumerate KeyStatusTypes which indicate the state of a key
+ enum KeyStatusType
+ {
+ kKeyStatusType_Usable,
+ kKeyStatusType_Expired,
+ kKeyStatusType_OutputNotAllowed,
+ kKeyStatusType_StatusPending,
+ kKeyStatusType_InternalError
+ };
+
+ // Used by sendKeysChange to report the usability status of each
+ // key to the app.
+ struct KeyStatus
+ {
+ Vector<uint8_t> mKeyId;
+ KeyStatusType mType;
+ };
+
DrmPlugin() {}
virtual ~DrmPlugin() {}
@@ -135,7 +165,8 @@
Vector<uint8_t> const &initData,
String8 const &mimeType, KeyType keyType,
KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl) = 0;
+ Vector<uint8_t> &request, String8 &defaultUrl,
+ KeyRequestType *keyRequestType) = 0;
//
// After a key response is received by the app, it is provided to the
@@ -315,11 +346,18 @@
}
protected:
- // Plugins call sendEvent to deliver events to the java app
+ // Plugins call these methods to deliver events to the java app
void sendEvent(EventType eventType, int extra,
Vector<uint8_t> const *sessionId,
Vector<uint8_t> const *data);
+ void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+ int64_t expiryTimeInMS);
+
+ void sendKeysChange(Vector<uint8_t> const *sessionId,
+ Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+ bool hasNewUsableKey);
+
private:
Mutex mEventLock;
sp<DrmPluginListener> mListener;
@@ -331,14 +369,20 @@
{
public:
virtual void sendEvent(DrmPlugin::EventType eventType, int extra,
- Vector<uint8_t> const *sesionId,
+ Vector<uint8_t> const *sessionId,
Vector<uint8_t> const *data) = 0;
+
+ virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+ int64_t expiryTimeInMS) = 0;
+
+ virtual void sendKeysChange(Vector<uint8_t> const *sessionId,
+ Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+ bool hasNewUsableKey) = 0;
};
inline void DrmPlugin::sendEvent(EventType eventType, int extra,
Vector<uint8_t> const *sessionId,
Vector<uint8_t> const *data) {
-
mEventLock.lock();
sp<DrmPluginListener> listener = mListener;
mEventLock.unlock();
@@ -348,6 +392,28 @@
}
}
+ inline void DrmPlugin::sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+ int64_t expiryTimeInMS) {
+ mEventLock.lock();
+ sp<DrmPluginListener> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+ }
+ }
+
+ inline void DrmPlugin::sendKeysChange(Vector<uint8_t> const *sessionId,
+ Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+ bool hasNewUsableKey) {
+ mEventLock.lock();
+ sp<DrmPluginListener> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ }
+ }
} // namespace android
#endif // DRM_API_H_
diff --git a/include/media/hardware/CryptoAPI.h b/include/media/hardware/CryptoAPI.h
index c800825..3e3257f 100644
--- a/include/media/hardware/CryptoAPI.h
+++ b/include/media/hardware/CryptoAPI.h
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+#include <media/stagefright/MediaErrors.h>
#include <utils/Errors.h>
+#include <utils/Vector.h>
#ifndef CRYPTO_API_H_
@@ -68,7 +70,18 @@
// the resolution of the video being decrypted. The media player should
// call this method when the resolution is determined and any time it
// is subsequently changed.
- virtual void notifyResolution(uint32_t width, uint32_t height) {}
+
+ virtual void notifyResolution(uint32_t /* width */, uint32_t /* height */) {}
+
+ // A MediaDrm session may be associated with a MediaCrypto session. The
+ // associated MediaDrm session is used to load decryption keys
+ // into the crypto/drm plugin. The keys are then referenced by key-id
+ // in the 'key' parameter to the decrypt() method.
+ // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if
+ // the session is not opened and a code from MediaErrors.h otherwise.
+ virtual status_t setMediaDrmSession(const Vector<uint8_t> & /*sessionId */) {
+ return ERROR_UNSUPPORTED;
+ }
// If the error returned falls into the range
// ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index d5f42be..1008c22 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -52,9 +52,9 @@
OMX_BOOL enable;
};
-// A pointer to this struct is passed to OMX_SetParameter() when the extension
-// index "OMX.google.android.index.storeMetaDataInBuffers"
-// is given.
+// A pointer to this struct is passed to OMX_SetParameter() when the extension index
+// "OMX.google.android.index.storeMetaDataInBuffers" or
+// "OMX.google.android.index.storeANWBufferInMetadata" is given.
//
// When meta data is stored in the video buffers passed between OMX clients
// and OMX components, interpretation of the buffer data is up to the
@@ -62,19 +62,33 @@
// some information helpful for the receiver to locate the actual data.
// The buffer receiver thus needs to know how to interpret what is stored
// in these buffers, with mechanisms pre-determined externally. How to
-// interpret the meta data is outside of the scope of this method.
+// interpret the meta data is outside of the scope of this parameter.
//
-// Currently, this is specifically used to pass meta data from video source
-// (camera component, for instance) to video encoder to avoid memcpying of
-// input video frame data. To do this, bStoreMetaData is set to OMX_TRUE.
-// If bStoreMetaData is set to false, real YUV frame data will be stored
-// in the buffers. In addition, if no OMX_SetParameter() call is made
-// with the corresponding extension index, real YUV data is stored
-// in the buffers.
+// Currently, this is used to pass meta data from video source (camera component, for instance) to
+// video encoder to avoid memcpying of input video frame data, as well as to pass dynamic output
+// buffer to video decoder. To do this, bStoreMetaData is set to OMX_TRUE.
//
-// For video decoder output port, the metadata buffer layout is defined below.
+// If bStoreMetaData is set to false, real YUV frame data will be stored in input buffers, and
+// the output buffers contain either real YUV frame data, or are themselves native handles as
+// directed by enable/use-android-native-buffer parameter settings.
+// In addition, if no OMX_SetParameter() call is made on a port with the corresponding extension
+// index, the component should not assume that the client is not using metadata mode for the port.
//
-// Metadata buffers are registered with the component using UseBuffer calls.
+// If the component supports this using the "OMX.google.android.index.storeANWBufferInMetadata"
+// extension and bStoreMetaData is set to OMX_TRUE, data is passed using the VideoNativeMetadata
+// layout as defined below. Each buffer will be accompanied by a fence. The fence must signal
+// before the buffer can be used (e.g. read from or written into). When returning such buffer to
+// the client, component must provide a new fence that must signal before the returned buffer can
+// be used (e.g. read from or written into). The component owns the incoming fenceFd, and must close
+// it when fence has signaled. The client will own and close the returned fence file descriptor.
+//
+// If the component supports this using the "OMX.google.android.index.storeMetaDataInBuffers"
+// extension and bStoreMetaData is set to OMX_TRUE, data is passed using VideoGrallocMetadata
+// (the layout of which is the VideoGrallocMetadata defined below). Camera input can be also passed
+// as "CameraSource", the layout of which is vendor dependent.
+//
+// Metadata buffers are registered with the component using UseBuffer calls, or can be allocated
+// by the component for encoder-metadata-output buffers.
struct StoreMetaDataInBuffersParams {
OMX_U32 nSize;
OMX_VERSIONTYPE nVersion;
@@ -84,9 +98,26 @@
// Meta data buffer layout used to transport output frames to the decoder for
// dynamic buffer handling.
-struct VideoDecoderOutputMetaData {
- MetadataBufferType eType;
- buffer_handle_t pHandle;
+struct VideoGrallocMetadata {
+ MetadataBufferType eType; // must be kMetadataBufferTypeGrallocSource
+#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+ OMX_PTR pHandle;
+#else
+ buffer_handle_t pHandle;
+#endif
+};
+
+// Legacy name for VideoGrallocMetadata struct.
+struct VideoDecoderOutputMetaData : public VideoGrallocMetadata {};
+
+struct VideoNativeMetadata {
+ MetadataBufferType eType; // must be kMetadataBufferTypeANWBuffer
+#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+ OMX_PTR pBuffer;
+#else
+ struct ANativeWindowBuffer* pBuffer;
+#endif
+ int nFenceFd; // -1 if unused
};
// A pointer to this struct is passed to OMX_SetParameter() when the extension
@@ -173,17 +204,17 @@
};
Type mType;
- size_t mNumPlanes; // number of planes
- size_t mWidth; // width of largest plane (unpadded, as in nFrameWidth)
- size_t mHeight; // height of largest plane (unpadded, as in nFrameHeight)
- size_t mBitDepth; // useable bit depth
+ uint32_t mNumPlanes; // number of planes
+ uint32_t mWidth; // width of largest plane (unpadded, as in nFrameWidth)
+ uint32_t mHeight; // height of largest plane (unpadded, as in nFrameHeight)
+ uint32_t mBitDepth; // useable bit depth
struct PlaneInfo {
- size_t mOffset; // offset of first pixel of the plane in bytes
- // from buffer offset
- size_t mColInc; // column increment in bytes
- size_t mRowInc; // row increment in bytes
- size_t mHorizSubsampling; // subsampling compared to the largest plane
- size_t mVertSubsampling; // subsampling compared to the largest plane
+ uint32_t mOffset; // offset of first pixel of the plane in bytes
+ // from buffer offset
+ uint32_t mColInc; // column increment in bytes
+ uint32_t mRowInc; // row increment in bytes
+ uint32_t mHorizSubsampling; // subsampling compared to the largest plane
+ uint32_t mVertSubsampling; // subsampling compared to the largest plane
};
PlaneInfo mPlane[MAX_NUM_PLANES];
};
diff --git a/include/media/hardware/MetadataBufferType.h b/include/media/hardware/MetadataBufferType.h
index 5876c40..b765203 100644
--- a/include/media/hardware/MetadataBufferType.h
+++ b/include/media/hardware/MetadataBufferType.h
@@ -77,28 +77,43 @@
* GRalloc buffer. The encoder needs to interpret this GRalloc handle
* and encode the frames.
* --------------------------------------------------------------
- * | kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
+ * | kMetadataBufferTypeGrallocSource | buffer_handle_t buffer |
* --------------------------------------------------------------
+ *
+ * See the VideoGrallocMetadata structure.
*/
kMetadataBufferTypeGrallocSource = 1,
/*
* kMetadataBufferTypeGraphicBuffer is used to indicate that
* the payload of the metadata buffers can be interpreted as
- * a GraphicBuffer. It is only to be used by software encoders.
- * In this case, the metadata that the encoder receives
- * will have a byte stream that consists of two parts:
+ * an ANativeWindowBuffer, and that a fence is provided.
+ *
+ * In this case, the metadata will have a byte stream that consists of three parts:
* 1. First, there is an integer indicating that the metadata
- * contains a GraphicBuffer (kMetadataBufferTypeGraphicBuffer)
- * 2. This is followed by the pointer to the GraphicBuffer that
- * is to be encoded. Encoder must not create a sp<> from this
- * graphic buffer, or free it, as it does not actually own this
- * buffer.
- * --------------------------------------------------------------
- * | kMetadataBufferTypeGraphicBuffer | sizeof(GraphicBuffer *) |
- * --------------------------------------------------------------
+ * contains an ANativeWindowBuffer (kMetadataBufferTypeANWBuffer)
+ * 2. This is followed by the pointer to the ANativeWindowBuffer.
+ * Codec must not free this buffer as it does not actually own this buffer.
+ * 3. Finally, there is an integer containing a fence file descriptor.
+ * The codec must wait on the fence before encoding or decoding into this
+ * buffer. When the buffer is returned, codec must replace this file descriptor
+ * with a new fence, that will be waited on before the buffer is replaced
+ * (encoder) or read (decoder).
+ * ---------------------------------
+ * | kMetadataBufferTypeANWBuffer |
+ * ---------------------------------
+ * | ANativeWindowBuffer *buffer |
+ * ---------------------------------
+ * | int fenceFd |
+ * ---------------------------------
+ *
+ * See the VideoNativeMetadata structure.
*/
- kMetadataBufferTypeGraphicBuffer = 2,
+ kMetadataBufferTypeANWBuffer = 2,
+
+ /* This value is used by framework, but is never used inside a metadata buffer */
+ kMetadataBufferTypeInvalid = -1,
+
// Add more here...
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 0f177a1..ae8430d 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -287,6 +287,7 @@
// case OMX_EventComponentResumed: return "ComponentResumed";
// case OMX_EventDynamicResourcesAvailable: return "DynamicResourcesAvailable";
// case OMX_EventPortFormatDetected: return "PortFormatDetected";
+ case OMX_EventOutputRendered: return "OutputRendered";
default: return def;
}
}
@@ -521,6 +522,9 @@
case OMX_IndexParamVideoHevc: return "ParamVideoHevc";
// case OMX_IndexParamSliceSegments: return "ParamSliceSegments";
case OMX_IndexConfigAutoFramerateConversion: return "ConfigAutoFramerateConversion";
+ case OMX_IndexConfigPriority: return "ConfigPriority";
+ case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate";
+ case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits";
default: return asString((OMX_INDEXTYPE)i, def);
}
}
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index 12f2b3b..521c223 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -503,12 +503,24 @@
OMX_EventResourcesAcquired, /**< component has been granted resources and is
automatically starting the state change from
OMX_StateWaitForResources to OMX_StateIdle. */
- OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */
- OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */
- OMX_EventPortFormatDetected, /**< Component has detected a supported format. */
- OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
- OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
- OMX_EventMax = 0x7FFFFFFF
+ OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */
+ OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */
+ OMX_EventPortFormatDetected, /**< Component has detected a supported format. */
+ OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+ OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+ /** Event when tunneled decoder has rendered an output
+ * nData1 must contain the number of timestamps returned
+ * pEventData must point to an array of the OMX_VIDEO_RENDEREVENTTYPE structs containing the
+ * render-timestamps of each frame. Component may batch rendered timestamps using this event,
+ * but must signal the event no more than 40ms after the first frame in the batch. The frames
+ * must be ordered by system timestamp inside and across batches.
+ *
+ * If component is doing frame-rate conversion, it must signal the render time of each
+ * converted frame, and must interpolate media timestamps for in-between frames.
+ */
+ OMX_EventOutputRendered = 0x7F000001,
+ OMX_EventMax = 0x7FFFFFFF
} OMX_EVENTTYPE;
typedef struct OMX_CALLBACKTYPE
diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h
index a5b9d18..f9b6f4b 100644
--- a/include/media/openmax/OMX_IVCommon.h
+++ b/include/media/openmax/OMX_IVCommon.h
@@ -157,6 +157,7 @@
* an acceptable range once that is done.
* */
OMX_COLOR_FormatAndroidOpaque = 0x7F000789,
+ OMX_COLOR_Format32BitRGBA8888 = 0x7F00A000,
/** Flexible 8-bit YUV format. Codec should report this format
* as being supported if it supports any YUV420 packed planar
* or semiplanar formats. When port is set to use this format,
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index ea3d0da..25bea1f 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -83,6 +83,9 @@
/* Other configurations */
OMX_IndexExtOtherStartUnused = OMX_IndexKhronosExtensions + 0x00800000,
OMX_IndexConfigAutoFramerateConversion, /**< reference: OMX_CONFIG_BOOLEANTYPE */
+ OMX_IndexConfigPriority, /**< reference: OMX_PARAM_U32TYPE */
+ OMX_IndexConfigOperatingRate, /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */
+ OMX_IndexParamConsumerUsageBits, /**< reference: OMX_PARAM_U32TYPE */
/* Time configurations */
OMX_IndexExtTimeStartUnused = OMX_IndexKhronosExtensions + 0x00900000,
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 3c97e14..34c0405 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -203,6 +203,12 @@
OMX_BOOL bEnableLoopFilterAcrossSlices;
} OMX_VIDEO_SLICESEGMENTSTYPE;
+/** Structure to return timestamps of rendered output frames for tunneled components */
+typedef struct OMX_VIDEO_RENDEREVENTTYPE {
+ OMX_S64 nMediaTimeUs; // timestamp of rendered video frame
+ OMX_S64 nSystemTimeNs; // system monotonic time at the time frame was rendered
+} OMX_VIDEO_RENDEREVENTTYPE;
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 2fa6ff9..cbe8733 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -39,6 +39,7 @@
enum {
eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
eLayerOpaque = 0x02, // SURFACE_OPAQUE
+ eLayerSecure = 0x80, // SECURE
};
enum {
@@ -48,10 +49,9 @@
eAlphaChanged = 0x00000008,
eMatrixChanged = 0x00000010,
eTransparentRegionChanged = 0x00000020,
- eVisibilityChanged = 0x00000040,
+ eFlagsChanged = 0x00000040,
eLayerStackChanged = 0x00000080,
eCropChanged = 0x00000100,
- eOpacityChanged = 0x00000200,
};
layer_state_t()
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 79decfe..d5860ef 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -26,6 +26,8 @@
IMemory.cpp \
IPCThreadState.cpp \
IPermissionController.cpp \
+ IProcessInfoService.cpp \
+ ProcessInfoService.cpp \
IServiceManager.cpp \
MemoryDealer.cpp \
MemoryBase.cpp \
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index c562c30..e4d8201 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -104,4 +104,13 @@
}
}
+int32_t AppOpsManager::permissionToOpCode(const String16& permission) {
+ sp<IAppOpsService> service = getService();
+ if (service != NULL) {
+ return service->permissionToOpCode(permission);
+ }
+ return -1;
+}
+
+
}; // namespace android
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 2d493c1..1339a67 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -49,9 +49,12 @@
status_t append(const char* txt, size_t len) {
if ((len+bufferPos) > bufferSize) {
- void* b = realloc(buffer, ((len+bufferPos)*3)/2);
+ size_t newSize = ((len+bufferPos)*3)/2;
+ if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow
+ void* b = realloc(buffer, newSize);
if (!b) return NO_MEMORY;
buffer = (char*)b;
+ bufferSize = newSize;
}
memcpy(buffer+bufferPos, txt, len);
bufferPos += len;
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 86abdc0..9558376 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -111,6 +111,17 @@
if (reply.readExceptionCode() != 0) return NULL;
return reply.readStrongBinder();
}
+
+
+ virtual int32_t permissionToOpCode(const String16& permission) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeString16(permission);
+ remote()->transact(PERMISSION_TO_OP_CODE_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) return -1;
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
@@ -187,6 +198,14 @@
reply->writeStrongBinder(token);
return NO_ERROR;
} break;
+ case PERMISSION_TO_OP_CODE_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ String16 permission = data.readString16();
+ const int32_t opCode = permissionToOpCode(permission);
+ reply->writeNoException();
+ reply->writeInt32(opCode);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index 8f3b7b4..e32c628 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -89,6 +89,47 @@
data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
remote()->transact(NOTE_RESET_AUDIO_TRANSACTION, data, &reply);
}
+
+ virtual void noteFlashlightOn(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_FLASHLIGHT_ON_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteFlashlightOff(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_FLASHLIGHT_OFF_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteStartCamera(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_START_CAMERA_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteStopCamera(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_STOP_CAMERA_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteResetCamera() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ remote()->transact(NOTE_RESET_CAMERA_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteResetFlashlight() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ remote()->transact(NOTE_RESET_FLASHLIGHT_TRANSACTION, data, &reply);
+ }
+
};
IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats");
@@ -155,6 +196,46 @@
reply->writeNoException();
return NO_ERROR;
} break;
+ case NOTE_FLASHLIGHT_ON_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteFlashlightOn(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_FLASHLIGHT_OFF_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteFlashlightOff(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_START_CAMERA_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteStartCamera(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_STOP_CAMERA_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteStopCamera(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_RESET_CAMERA_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ noteResetCamera();
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_RESET_FLASHLIGHT_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ noteResetFlashlight();
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
index 8c60dc4..2fcd3d9 100644
--- a/libs/binder/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "IInterface"
+#include <utils/Log.h>
#include <binder/IInterface.h>
namespace android {
@@ -41,6 +43,25 @@
return iface->onAsBinder();
}
+
// ---------------------------------------------------------------------------
}; // namespace android
+
+extern "C" {
+
+void _ZN7android10IInterface8asBinderEv(void *retval, void* self) {
+ ALOGW("deprecated asBinder call, please update your code");
+ //ALOGI("self: %p, retval: %p", self, retval);
+ android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>;
+ *ret = android::IInterface::asBinder((android::IInterface*)self);
+}
+
+void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) {
+ ALOGW("deprecated asBinder call, please update your code");
+ //ALOGI("self: %p, retval: %p", self, retval);
+ android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>;
+ *ret = android::IInterface::asBinder((android::IInterface*)self);
+}
+
+} // extern "C"
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 18a4e0d..a237684 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -399,6 +399,18 @@
talkWithDriver(false);
}
+void IPCThreadState::blockUntilThreadAvailable()
+{
+ pthread_mutex_lock(&mProcess->mThreadCountLock);
+ while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) {
+ ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n",
+ static_cast<unsigned long>(mProcess->mExecutingThreadsCount),
+ static_cast<unsigned long>(mProcess->mMaxThreads));
+ pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock);
+ }
+ pthread_mutex_unlock(&mProcess->mThreadCountLock);
+}
+
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
@@ -414,8 +426,17 @@
<< getReturnString(cmd) << endl;
}
+ pthread_mutex_lock(&mProcess->mThreadCountLock);
+ mProcess->mExecutingThreadsCount++;
+ pthread_mutex_unlock(&mProcess->mThreadCountLock);
+
result = executeCommand(cmd);
+ pthread_mutex_lock(&mProcess->mThreadCountLock);
+ mProcess->mExecutingThreadsCount--;
+ pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
+ pthread_mutex_unlock(&mProcess->mThreadCountLock);
+
// After executing the command, ensure that the thread is returned to the
// foreground cgroup before rejoining the pool. The driver takes care of
// restoring the priority, but doesn't do anything with cgroups so we
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 437113d..6bba996 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -48,6 +48,36 @@
if (reply.readExceptionCode() != 0) return 0;
return reply.readInt32() != 0;
}
+
+ virtual void getPackagesForUid(const uid_t uid, Vector<String16>& packages)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(GET_PACKAGES_FOR_UID_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) {
+ return;
+ }
+ const int32_t size = reply.readInt32();
+ if (size <= 0) {
+ return;
+ }
+ for (int i = 0; i < size; i++) {
+ packages.push(reply.readString16());
+ }
+ }
+
+ virtual bool isRuntimePermission(const String16& permission)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeString16(permission);
+ remote()->transact(IS_RUNTIME_PERMISSION_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) return false;
+ return reply.readInt32() != 0;
+ }
};
IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
@@ -57,7 +87,6 @@
status_t BnPermissionController::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- //printf("PermissionController received: "); data.print();
switch(code) {
case CHECK_PERMISSION_TRANSACTION: {
CHECK_INTERFACE(IPermissionController, data, reply);
@@ -69,6 +98,30 @@
reply->writeInt32(res ? 1 : 0);
return NO_ERROR;
} break;
+
+ case GET_PACKAGES_FOR_UID_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ int32_t uid = data.readInt32();
+ Vector<String16> packages;
+ getPackagesForUid(uid, packages);
+ reply->writeNoException();
+ size_t size = packages.size();
+ reply->writeInt32(size);
+ for (size_t i = 0; i < size; i++) {
+ reply->writeString16(packages[i]);
+ }
+ return NO_ERROR;
+ } break;
+
+ case IS_RUNTIME_PERMISSION_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ String16 permission = data.readString16();
+ const bool res = isRuntimePermission(permission);
+ reply->writeNoException();
+ reply->writeInt32(res ? 1 : 0);
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
new file mode 100644
index 0000000..d86eb27
--- /dev/null
+++ b/libs/binder/IProcessInfoService.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2015 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 <binder/IProcessInfoService.h>
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <sys/types.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpProcessInfoService : public BpInterface<IProcessInfoService> {
+public:
+ BpProcessInfoService(const sp<IBinder>& impl)
+ : BpInterface<IProcessInfoService>(impl) {}
+
+ virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
+ /*out*/ int32_t* states)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IProcessInfoService::getInterfaceDescriptor());
+ data.writeInt32Array(length, pids);
+ data.writeInt32(length); // write length of output array, used by java AIDL stubs
+ status_t err = remote()->transact(GET_PROCESS_STATES_FROM_PIDS, data, &reply);
+ if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ return err;
+ }
+ int32_t replyLen = reply.readInt32();
+ if (static_cast<size_t>(replyLen) != length) {
+ return NOT_ENOUGH_DATA;
+ }
+ if (replyLen > 0 && (err = reply.read(states, length * sizeof(*states))) != NO_ERROR) {
+ return err;
+ }
+ return reply.readInt32();
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService");
+
+// ----------------------------------------------------------------------
+
+status_t BnProcessInfoService::onTransact( uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ switch(code) {
+ case GET_PROCESS_STATES_FROM_PIDS: {
+ CHECK_INTERFACE(IProcessInfoService, data, reply);
+ int32_t arrayLen = data.readInt32();
+ if (arrayLen <= 0) {
+ reply->writeNoException();
+ reply->writeInt32(0);
+ reply->writeInt32(NOT_ENOUGH_DATA);
+ return NO_ERROR;
+ }
+
+ size_t len = static_cast<size_t>(arrayLen);
+ int32_t pids[len];
+ status_t res = data.read(pids, len * sizeof(*pids));
+
+ // Ignore output array length returned in the parcel here, as the states array must
+ // always be the same length as the input PIDs array.
+ int32_t states[len];
+ for (size_t i = 0; i < len; i++) states[i] = -1;
+ if (res == NO_ERROR) {
+ res = getProcessStatesFromPids(len, /*in*/ pids, /*out*/ states);
+ }
+ reply->writeNoException();
+ reply->writeInt32Array(len, states);
+ reply->writeInt32(res);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 24c8a77..7a4ddc4 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -54,7 +54,17 @@
// ---------------------------------------------------------------------------
-#define PAD_SIZE(s) (((s)+3)&~3)
+// This macro should never be used at runtime, as a too large value
+// of s could cause an integer overflow. Instead, you should always
+// use the wrapper function pad_size()
+#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3)
+
+static size_t pad_size(size_t s) {
+ if (s > (SIZE_T_MAX - 3)) {
+ abort();
+ }
+ return PAD_SIZE_UNSAFE(s);
+}
// Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
@@ -62,9 +72,6 @@
// Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER
#define EX_HAS_REPLY_HEADER -128
-// Maximum size of a blob to transfer in-place.
-static const size_t IN_PLACE_BLOB_LIMIT = 40 * 1024;
-
// XXX This can be made public if we want to provide
// support for typed data.
struct small_flat_data
@@ -79,6 +86,15 @@
static size_t gParcelGlobalAllocSize = 0;
static size_t gParcelGlobalAllocCount = 0;
+// Maximum size of a blob to transfer in-place.
+static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
+
+enum {
+ BLOB_INPLACE = 0,
+ BLOB_ASHMEM_IMMUTABLE = 1,
+ BLOB_ASHMEM_MUTABLE = 2,
+};
+
void acquire_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who)
{
@@ -355,6 +371,12 @@
status_t Parcel::setDataSize(size_t size)
{
+ if (size > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
status_t err;
err = continueWrite(size);
if (err == NO_ERROR) {
@@ -366,18 +388,36 @@
void Parcel::setDataPosition(size_t pos) const
{
+ if (pos > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ abort();
+ }
+
mDataPos = pos;
mNextObjectHint = 0;
}
status_t Parcel::setDataCapacity(size_t size)
{
+ if (size > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
if (size > mDataCapacity) return continueWrite(size);
return NO_ERROR;
}
status_t Parcel::setData(const uint8_t* buffer, size_t len)
{
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
status_t err = restartWrite(len);
if (err == NO_ERROR) {
memcpy(const_cast<uint8_t*>(data()), buffer, len);
@@ -401,6 +441,12 @@
return NO_ERROR;
}
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
// range checks against the source parcel size
if ((offset > parcel->mDataSize)
|| (len > parcel->mDataSize)
@@ -411,7 +457,7 @@
// Count objects in range
for (int i = 0; i < (int) size; i++) {
size_t off = objects[i];
- if ((off >= offset) && (off < offset + len)) {
+ if ((off >= offset) && (off + sizeof(flat_binder_object) <= offset + len)) {
if (firstIndex == -1) {
firstIndex = i;
}
@@ -438,7 +484,8 @@
if (numObjects > 0) {
// grow objects
if (mObjectsCapacity < mObjectsSize + numObjects) {
- int newSize = ((mObjectsSize + numObjects)*3)/2;
+ size_t newSize = ((mObjectsSize + numObjects)*3)/2;
+ if (newSize < mObjectsSize) return NO_MEMORY; // overflow
binder_size_t *objects =
(binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == (binder_size_t*)0) {
@@ -476,6 +523,11 @@
return err;
}
+bool Parcel::allowFds() const
+{
+ return mAllowFds;
+}
+
bool Parcel::pushAllowFds(bool allowFds)
{
const bool origValue = mAllowFds;
@@ -561,6 +613,12 @@
status_t Parcel::finishWrite(size_t len)
{
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
//printf("Finish write of %d\n", len);
mDataPos += len;
ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos);
@@ -574,6 +632,12 @@
status_t Parcel::writeUnpadded(const void* data, size_t len)
{
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
size_t end = mDataPos + len;
if (end < mDataPos) {
// integer overflow
@@ -593,6 +657,12 @@
status_t Parcel::write(const void* data, size_t len)
{
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
void* const d = writeInplace(len);
if (d) {
memcpy(d, data, len);
@@ -603,7 +673,13 @@
void* Parcel::writeInplace(size_t len)
{
- const size_t padded = PAD_SIZE(len);
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return NULL;
+ }
+
+ const size_t padded = pad_size(len);
// sanity check for integer overflow
if (mDataPos+padded < mDataPos) {
@@ -652,20 +728,32 @@
}
status_t Parcel::writeInt32Array(size_t len, const int32_t *val) {
- if (!val) {
- return writeAligned(-1);
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
}
- status_t ret = writeAligned(len);
+
+ if (!val) {
+ return writeInt32(-1);
+ }
+ status_t ret = writeInt32(static_cast<uint32_t>(len));
if (ret == NO_ERROR) {
ret = write(val, len * sizeof(*val));
}
return ret;
}
status_t Parcel::writeByteArray(size_t len, const uint8_t *val) {
- if (!val) {
- return writeAligned(-1);
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
}
- status_t ret = writeAligned(len);
+
+ if (!val) {
+ return writeInt32(-1);
+ }
+ status_t ret = writeInt32(static_cast<uint32_t>(len));
if (ret == NO_ERROR) {
ret = write(val, len * sizeof(*val));
}
@@ -810,45 +898,24 @@
return err;
}
-// WARNING: This method must stay in sync with
-// Parcelable.Creator<ParcelFileDescriptor> CREATOR
-// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java
-status_t Parcel::writeParcelFileDescriptor(int fd, int commChannel) {
- status_t status;
-
- if (fd < 0) {
- status = writeInt32(0); // ParcelFileDescriptor is null
- if (status) return status;
- } else {
- status = writeInt32(1); // ParcelFileDescriptor is not null
- if (status) return status;
- status = writeDupFileDescriptor(fd);
- if (status) return status;
- if (commChannel < 0) {
- status = writeInt32(0); // commChannel is null
- if (status) return status;
- } else {
- status = writeInt32(1); // commChannel is not null
- if (status) return status;
- status = writeDupFileDescriptor(commChannel);
- }
- }
- return status;
-}
-
-status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)
+status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
{
- status_t status;
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
- if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) {
+ status_t status;
+ if (!mAllowFds || len <= BLOB_INPLACE_LIMIT) {
ALOGV("writeBlob: write in place");
- status = writeInt32(0);
+ status = writeInt32(BLOB_INPLACE);
if (status) return status;
void* ptr = writeInplace(len);
if (!ptr) return NO_MEMORY;
- outBlob->init(false /*mapped*/, ptr, len);
+ outBlob->init(-1, ptr, len, false);
return NO_ERROR;
}
@@ -856,6 +923,8 @@
int fd = ashmem_create_region("Parcel Blob", len);
if (fd < 0) return NO_MEMORY;
+ mBlobAshmemSize += len;
+
int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
if (result < 0) {
status = result;
@@ -864,15 +933,17 @@
if (ptr == MAP_FAILED) {
status = -errno;
} else {
- result = ashmem_set_prot_region(fd, PROT_READ);
+ if (!mutableCopy) {
+ result = ashmem_set_prot_region(fd, PROT_READ);
+ }
if (result < 0) {
status = result;
} else {
- status = writeInt32(1);
+ status = writeInt32(mutableCopy ? BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE);
if (!status) {
status = writeFileDescriptor(fd, true /*takeOwnership*/);
if (!status) {
- outBlob->init(true /*mapped*/, ptr, len);
+ outBlob->init(fd, ptr, len, mutableCopy);
return NO_ERROR;
}
}
@@ -884,6 +955,15 @@
return status;
}
+status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd)
+{
+ // Must match up with what's done in writeBlob.
+ if (!mAllowFds) return FDS_NOT_ALLOWED;
+ status_t status = writeInt32(BLOB_ASHMEM_IMMUTABLE);
+ if (status) return status;
+ return writeDupFileDescriptor(fd);
+}
+
status_t Parcel::write(const FlattenableHelperInterface& val)
{
status_t err;
@@ -892,6 +972,12 @@
const size_t len = val.getFlattenedSize();
const size_t fd_count = val.getFdCount();
+ if ((len > INT32_MAX) || (fd_count > INT32_MAX)) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
err = this->writeInt32(len);
if (err) return err;
@@ -899,7 +985,7 @@
if (err) return err;
// payload
- void* const buf = this->writeInplace(PAD_SIZE(len));
+ void* const buf = this->writeInplace(pad_size(len));
if (buf == NULL)
return BAD_VALUE;
@@ -928,6 +1014,15 @@
restart_write:
*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
+ // remember if it's a file descriptor
+ if (val.type == BINDER_TYPE_FD) {
+ if (!mAllowFds) {
+ // fail before modifying our object index
+ return FDS_NOT_ALLOWED;
+ }
+ mHasFds = mFdsKnown = true;
+ }
+
// Need to write meta-data?
if (nullMetaData || val.binder != 0) {
mObjects[mObjectsSize] = mDataPos;
@@ -935,14 +1030,6 @@
mObjectsSize++;
}
- // remember if it's a file descriptor
- if (val.type == BINDER_TYPE_FD) {
- if (!mAllowFds) {
- return FDS_NOT_ALLOWED;
- }
- mHasFds = mFdsKnown = true;
- }
-
return finishWrite(sizeof(flat_binder_object));
}
@@ -952,6 +1039,7 @@
}
if (!enoughObjects) {
size_t newSize = ((mObjectsSize+2)*3)/2;
+ if (newSize < mObjectsSize) return NO_MEMORY; // overflow
binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == NULL) return NO_MEMORY;
mObjects = objects;
@@ -973,10 +1061,16 @@
status_t Parcel::read(void* outData, size_t len) const
{
- if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize
- && len <= PAD_SIZE(len)) {
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
+ if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
+ && len <= pad_size(len)) {
memcpy(outData, mData+mDataPos, len);
- mDataPos += PAD_SIZE(len);
+ mDataPos += pad_size(len);
ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
return NO_ERROR;
}
@@ -985,10 +1079,16 @@
const void* Parcel::readInplace(size_t len) const
{
- if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize
- && len <= PAD_SIZE(len)) {
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return NULL;
+ }
+
+ if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
+ && len <= pad_size(len)) {
const void* data = mData+mDataPos;
- mDataPos += PAD_SIZE(len);
+ mDataPos += pad_size(len);
ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
return data;
}
@@ -997,7 +1097,7 @@
template<class T>
status_t Parcel::readAligned(T *pArg) const {
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
if ((mDataPos+sizeof(T)) <= mDataSize) {
const void* data = mData+mDataPos;
@@ -1021,7 +1121,7 @@
template<class T>
status_t Parcel::writeAligned(T val) {
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
@@ -1162,7 +1262,7 @@
const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
if (eos) {
const size_t len = eos - str;
- mDataPos += PAD_SIZE(len+1);
+ mDataPos += pad_size(len+1);
ALOGV("readCString Setting data pos of %p to %zu", this, mDataPos);
return str;
}
@@ -1245,6 +1345,10 @@
if (err != NO_ERROR) return 0;
native_handle* h = native_handle_create(numFds, numInts);
+ if (!h) {
+ return 0;
+ }
+
for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
h->data[i] = dup(readFileDescriptor());
if (h->data[i] < 0) err = BAD_VALUE;
@@ -1272,46 +1376,31 @@
return BAD_TYPE;
}
-// WARNING: This method must stay in sync with writeToParcel()
-// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java
-int Parcel::readParcelFileDescriptor(int& outCommChannel) const {
- int fd;
- outCommChannel = -1;
-
- if (readInt32() == 0) {
- fd = -1;
- } else {
- fd = readFileDescriptor();
- if (fd >= 0 && readInt32() != 0) {
- outCommChannel = readFileDescriptor();
- }
- }
- return fd;
-}
-
status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
{
- int32_t useAshmem;
- status_t status = readInt32(&useAshmem);
+ int32_t blobType;
+ status_t status = readInt32(&blobType);
if (status) return status;
- if (!useAshmem) {
+ if (blobType == BLOB_INPLACE) {
ALOGV("readBlob: read in place");
const void* ptr = readInplace(len);
if (!ptr) return BAD_VALUE;
- outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len);
+ outBlob->init(-1, const_cast<void*>(ptr), len, false);
return NO_ERROR;
}
ALOGV("readBlob: read from ashmem");
+ bool isMutable = (blobType == BLOB_ASHMEM_MUTABLE);
int fd = readFileDescriptor();
if (fd == int(BAD_TYPE)) return BAD_VALUE;
- void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+ void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
+ MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) return NO_MEMORY;
- outBlob->init(true /*mapped*/, ptr, len);
+ outBlob->init(fd, ptr, len, isMutable);
return NO_ERROR;
}
@@ -1321,8 +1410,14 @@
const size_t len = this->readInt32();
const size_t fd_count = this->readInt32();
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
// payload
- void const* const buf = this->readInplace(PAD_SIZE(len));
+ void const* const buf = this->readInplace(pad_size(len));
if (buf == NULL)
return BAD_VALUE;
@@ -1561,6 +1656,12 @@
status_t Parcel::growData(size_t len)
{
+ if (len > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
size_t newSize = ((mDataSize+len)*3)/2;
return (newSize <= mDataSize)
? (status_t) NO_MEMORY
@@ -1569,6 +1670,12 @@
status_t Parcel::restartWrite(size_t desired)
{
+ if (desired > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
if (mOwner) {
freeData();
return continueWrite(desired);
@@ -1609,6 +1716,12 @@
status_t Parcel::continueWrite(size_t desired)
{
+ if (desired > INT32_MAX) {
+ // don't accept size_t values which may have come from an
+ // inadvertent conversion from a negative int.
+ return BAD_VALUE;
+ }
+
// If shrinking, first adjust for any objects that appear
// after the new data size.
size_t objectsSize = mObjectsSize;
@@ -1777,6 +1890,7 @@
mFdsKnown = true;
mAllowFds = true;
mOwner = NULL;
+ mBlobAshmemSize = 0;
}
void Parcel::scanForFds() const
@@ -1794,10 +1908,15 @@
mFdsKnown = true;
}
+size_t Parcel::getBlobAshmemSize() const
+{
+ return mBlobAshmemSize;
+}
+
// --- Parcel::Blob ---
Parcel::Blob::Blob() :
- mMapped(false), mData(NULL), mSize(0) {
+ mFd(-1), mData(NULL), mSize(0), mMutable(false) {
}
Parcel::Blob::~Blob() {
@@ -1805,22 +1924,24 @@
}
void Parcel::Blob::release() {
- if (mMapped && mData) {
+ if (mFd != -1 && mData) {
::munmap(mData, mSize);
}
clear();
}
-void Parcel::Blob::init(bool mapped, void* data, size_t size) {
- mMapped = mapped;
+void Parcel::Blob::init(int fd, void* data, size_t size, bool isMutable) {
+ mFd = fd;
mData = data;
mSize = size;
+ mMutable = isMutable;
}
void Parcel::Blob::clear() {
- mMapped = false;
+ mFd = -1;
mData = NULL;
mSize = 0;
+ mMutable = false;
}
}; // namespace android
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
new file mode 100644
index 0000000..fb28643
--- /dev/null
+++ b/libs/binder/ProcessInfoService.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 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 <binder/ProcessInfoService.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+namespace android {
+
+ProcessInfoService::ProcessInfoService() {
+ updateBinderLocked();
+}
+
+status_t ProcessInfoService::getProcessStatesImpl(size_t length, /*in*/ int32_t* pids,
+ /*out*/ int32_t* states) {
+ status_t err = NO_ERROR;
+ sp<IProcessInfoService> pis;
+ mProcessInfoLock.lock();
+ pis = mProcessInfoService;
+ mProcessInfoLock.unlock();
+
+ for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) {
+
+ if (pis != NULL) {
+ err = pis->getProcessStatesFromPids(length, /*in*/ pids, /*out*/ states);
+ if (err == NO_ERROR) return NO_ERROR; // success
+ if (IInterface::asBinder(pis)->isBinderAlive()) return err;
+ }
+ sleep(1);
+
+ mProcessInfoLock.lock();
+ if (pis == mProcessInfoService) {
+ updateBinderLocked();
+ }
+ pis = mProcessInfoService;
+ mProcessInfoLock.unlock();
+ }
+
+ ALOGW("%s: Could not retrieve process states from ProcessInfoService after %d retries.",
+ __FUNCTION__, BINDER_ATTEMPT_LIMIT);
+
+ return TIMED_OUT;
+}
+
+void ProcessInfoService::updateBinderLocked() {
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != NULL) {
+ const String16 name("processinfo");
+ mProcessInfoService = interface_cast<IProcessInfoService>(sm->checkService(name));
+ }
+}
+
+ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService);
+
+}; // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 4109575..016d3c5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -42,12 +42,13 @@
#include <sys/stat.h>
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
+#define DEFAULT_MAX_BINDER_THREADS 15
// ---------------------------------------------------------------------------
namespace android {
-
+
class PoolThread : public Thread
{
public:
@@ -294,7 +295,9 @@
status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
status_t result = NO_ERROR;
- if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) {
+ if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) {
+ mMaxThreads = maxThreads;
+ } else {
result = -errno;
ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
}
@@ -322,7 +325,7 @@
close(fd);
fd = -1;
}
- size_t maxThreads = 15;
+ size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
@@ -336,6 +339,10 @@
ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
+ , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
+ , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
+ , mExecutingThreadsCount(0)
+ , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
@@ -343,6 +350,10 @@
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
+ // XXX Ideally, there should be a specific define for whether we
+ // have mmap (or whether we could possibly have the kernel module
+ // availabla).
+#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
@@ -351,6 +362,9 @@
close(mDriverFD);
mDriverFD = -1;
}
+#else
+ mDriverFD = -1;
+#endif
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index ae796b1..bb3e1b0 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -38,156 +38,169 @@
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
ATRACE_CALL();
- Mutex::Autolock lock(mCore->mMutex);
- // Check that the consumer doesn't currently have the maximum number of
- // buffers acquired. We allow the max buffer count to be exceeded by one
- // buffer so that the consumer can successfully set up the newly acquired
- // buffer before releasing the old one.
- int numAcquiredBuffers = 0;
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
- ++numAcquiredBuffers;
+ int numDroppedBuffers = 0;
+ sp<IProducerListener> listener;
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+
+ // Check that the consumer doesn't currently have the maximum number of
+ // buffers acquired. We allow the max buffer count to be exceeded by one
+ // buffer so that the consumer can successfully set up the newly acquired
+ // buffer before releasing the old one.
+ int numAcquiredBuffers = 0;
+ for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+ ++numAcquiredBuffers;
+ }
}
- }
- if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
- BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
- numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
- return INVALID_OPERATION;
- }
+ if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+ BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
+ numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
+ return INVALID_OPERATION;
+ }
- // Check if the queue is empty.
- // In asynchronous mode the list is guaranteed to be one buffer deep,
- // while in synchronous mode we use the oldest buffer.
- if (mCore->mQueue.empty()) {
- return NO_BUFFER_AVAILABLE;
- }
+ // Check if the queue is empty.
+ // In asynchronous mode the list is guaranteed to be one buffer deep,
+ // while in synchronous mode we use the oldest buffer.
+ if (mCore->mQueue.empty()) {
+ return NO_BUFFER_AVAILABLE;
+ }
- BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
+ BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
- // If expectedPresent is specified, we may not want to return a buffer yet.
- // If it's specified and there's more than one buffer queued, we may want
- // to drop a buffer.
- if (expectedPresent != 0) {
- const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
+ // If expectedPresent is specified, we may not want to return a buffer yet.
+ // If it's specified and there's more than one buffer queued, we may want
+ // to drop a buffer.
+ if (expectedPresent != 0) {
+ const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
- // The 'expectedPresent' argument indicates when the buffer is expected
- // to be presented on-screen. If the buffer's desired present time is
- // earlier (less) than expectedPresent -- meaning it will be displayed
- // on time or possibly late if we show it as soon as possible -- we
- // acquire and return it. If we don't want to display it until after the
- // expectedPresent time, we return PRESENT_LATER without acquiring it.
- //
- // To be safe, we don't defer acquisition if expectedPresent is more
- // than one second in the future beyond the desired present time
- // (i.e., we'd be holding the buffer for a long time).
- //
- // NOTE: Code assumes monotonic time values from the system clock
- // are positive.
+ // The 'expectedPresent' argument indicates when the buffer is expected
+ // to be presented on-screen. If the buffer's desired present time is
+ // earlier (less) than expectedPresent -- meaning it will be displayed
+ // on time or possibly late if we show it as soon as possible -- we
+ // acquire and return it. If we don't want to display it until after the
+ // expectedPresent time, we return PRESENT_LATER without acquiring it.
+ //
+ // To be safe, we don't defer acquisition if expectedPresent is more
+ // than one second in the future beyond the desired present time
+ // (i.e., we'd be holding the buffer for a long time).
+ //
+ // NOTE: Code assumes monotonic time values from the system clock
+ // are positive.
- // Start by checking to see if we can drop frames. We skip this check if
- // the timestamps are being auto-generated by Surface. If the app isn't
- // generating timestamps explicitly, it probably doesn't want frames to
- // be discarded based on them.
- while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
- const BufferItem& bufferItem(mCore->mQueue[1]);
+ // Start by checking to see if we can drop frames. We skip this check if
+ // the timestamps are being auto-generated by Surface. If the app isn't
+ // generating timestamps explicitly, it probably doesn't want frames to
+ // be discarded based on them.
+ while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+ const BufferItem& bufferItem(mCore->mQueue[1]);
- // If dropping entry[0] would leave us with a buffer that the
- // consumer is not yet ready for, don't drop it.
- if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
- break;
+ // If dropping entry[0] would leave us with a buffer that the
+ // consumer is not yet ready for, don't drop it.
+ if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
+ break;
+ }
+
+ // If entry[1] is timely, drop entry[0] (and repeat). We apply an
+ // additional criterion here: we only drop the earlier buffer if our
+ // desiredPresent falls within +/- 1 second of the expected present.
+ // Otherwise, bogus desiredPresent times (e.g., 0 or a small
+ // relative timestamp), which normally mean "ignore the timestamp
+ // and acquire immediately", would cause us to drop frames.
+ //
+ // We may want to add an additional criterion: don't drop the
+ // earlier buffer if entry[1]'s fence hasn't signaled yet.
+ nsecs_t desiredPresent = bufferItem.mTimestamp;
+ if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+ desiredPresent > expectedPresent) {
+ // This buffer is set to display in the near future, or
+ // desiredPresent is garbage. Either way we don't want to drop
+ // the previous buffer just to get this on the screen sooner.
+ BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
+ PRId64 " (%" PRId64 ") now=%" PRId64,
+ desiredPresent, expectedPresent,
+ desiredPresent - expectedPresent,
+ systemTime(CLOCK_MONOTONIC));
+ break;
+ }
+
+ BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
+ " size=%zu",
+ desiredPresent, expectedPresent, mCore->mQueue.size());
+ if (mCore->stillTracking(front)) {
+ // Front buffer is still in mSlots, so mark the slot as free
+ mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
+ mCore->mFreeBuffers.push_back(front->mSlot);
+ listener = mCore->mConnectedProducerListener;
+ ++numDroppedBuffers;
+ }
+ mCore->mQueue.erase(front);
+ front = mCore->mQueue.begin();
}
- // If entry[1] is timely, drop entry[0] (and repeat). We apply an
- // additional criterion here: we only drop the earlier buffer if our
- // desiredPresent falls within +/- 1 second of the expected present.
- // Otherwise, bogus desiredPresent times (e.g., 0 or a small
- // relative timestamp), which normally mean "ignore the timestamp
- // and acquire immediately", would cause us to drop frames.
- //
- // We may want to add an additional criterion: don't drop the
- // earlier buffer if entry[1]'s fence hasn't signaled yet.
- nsecs_t desiredPresent = bufferItem.mTimestamp;
- if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
- desiredPresent > expectedPresent) {
- // This buffer is set to display in the near future, or
- // desiredPresent is garbage. Either way we don't want to drop
- // the previous buffer just to get this on the screen sooner.
- BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
- PRId64 " (%" PRId64 ") now=%" PRId64,
+ // See if the front buffer is ready to be acquired
+ nsecs_t desiredPresent = front->mTimestamp;
+ bool bufferIsDue = desiredPresent <= expectedPresent ||
+ desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
+ bool consumerIsReady = maxFrameNumber > 0 ?
+ front->mFrameNumber <= maxFrameNumber : true;
+ if (!bufferIsDue || !consumerIsReady) {
+ BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
+ " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
+ " consumer=%" PRIu64,
desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
- systemTime(CLOCK_MONOTONIC));
- break;
+ systemTime(CLOCK_MONOTONIC),
+ front->mFrameNumber, maxFrameNumber);
+ return PRESENT_LATER;
}
- BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
- " size=%zu",
- desiredPresent, expectedPresent, mCore->mQueue.size());
- if (mCore->stillTracking(front)) {
- // Front buffer is still in mSlots, so mark the slot as free
- mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
- mCore->mFreeBuffers.push_back(front->mSlot);
- }
- mCore->mQueue.erase(front);
- front = mCore->mQueue.begin();
- }
-
- // See if the front buffer is ready to be acquired
- nsecs_t desiredPresent = front->mTimestamp;
- bool bufferIsDue = desiredPresent <= expectedPresent ||
- desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
- bool consumerIsReady = maxFrameNumber > 0 ?
- front->mFrameNumber <= maxFrameNumber : true;
- if (!bufferIsDue || !consumerIsReady) {
- BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
- " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
- " consumer=%" PRIu64,
- desiredPresent, expectedPresent,
+ BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
+ "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
- systemTime(CLOCK_MONOTONIC),
- front->mFrameNumber, maxFrameNumber);
- return PRESENT_LATER;
+ systemTime(CLOCK_MONOTONIC));
}
- BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
- "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
- desiredPresent - expectedPresent,
- systemTime(CLOCK_MONOTONIC));
+ int slot = front->mSlot;
+ *outBuffer = *front;
+ ATRACE_BUFFER_INDEX(slot);
+
+ BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
+ slot, front->mFrameNumber, front->mGraphicBuffer->handle);
+ // If the front buffer is still being tracked, update its slot state
+ if (mCore->stillTracking(front)) {
+ mSlots[slot].mAcquireCalled = true;
+ mSlots[slot].mNeedsCleanupOnRelease = false;
+ mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
+ mSlots[slot].mFence = Fence::NO_FENCE;
+ }
+
+ // If the buffer has previously been acquired by the consumer, set
+ // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
+ // on the consumer side
+ if (outBuffer->mAcquireCalled) {
+ outBuffer->mGraphicBuffer = NULL;
+ }
+
+ mCore->mQueue.erase(front);
+
+ // We might have freed a slot while dropping old buffers, or the producer
+ // may be blocked waiting for the number of buffers in the queue to
+ // decrease.
+ mCore->mDequeueCondition.broadcast();
+
+ ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+
+ mCore->validateConsistencyLocked();
}
- int slot = front->mSlot;
- *outBuffer = *front;
- ATRACE_BUFFER_INDEX(slot);
-
- BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
- slot, front->mFrameNumber, front->mGraphicBuffer->handle);
- // If the front buffer is still being tracked, update its slot state
- if (mCore->stillTracking(front)) {
- mSlots[slot].mAcquireCalled = true;
- mSlots[slot].mNeedsCleanupOnRelease = false;
- mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
- mSlots[slot].mFence = Fence::NO_FENCE;
+ if (listener != NULL) {
+ for (int i = 0; i < numDroppedBuffers; ++i) {
+ listener->onBufferReleased();
+ }
}
- // If the buffer has previously been acquired by the consumer, set
- // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
- // on the consumer side
- if (outBuffer->mAcquireCalled) {
- outBuffer->mGraphicBuffer = NULL;
- }
-
- mCore->mQueue.erase(front);
-
- // We might have freed a slot while dropping old buffers, or the producer
- // may be blocked waiting for the number of buffers in the queue to
- // decrease.
- mCore->mDequeueCondition.broadcast();
-
- ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
-
- mCore->validateConsistencyLocked();
-
return NO_ERROR;
}
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
index 8e09e7c..f581b5c 100644
--- a/libs/gui/ISensorServer.cpp
+++ b/libs/gui/ISensorServer.cpp
@@ -35,6 +35,7 @@
enum {
GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION,
CREATE_SENSOR_EVENT_CONNECTION,
+ ENABLE_DATA_INJECTION
};
class BpSensorServer : public BpInterface<ISensorServer>
@@ -47,10 +48,11 @@
virtual ~BpSensorServer();
- virtual Vector<Sensor> getSensorList()
+ virtual Vector<Sensor> getSensorList(const String16& opPackageName)
{
Parcel data, reply;
data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ data.writeString16(opPackageName);
remote()->transact(GET_SENSOR_LIST, data, &reply);
Sensor s;
Vector<Sensor> v;
@@ -63,13 +65,24 @@
return v;
}
- virtual sp<ISensorEventConnection> createSensorEventConnection()
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+ int mode, const String16& opPackageName)
{
Parcel data, reply;
data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ data.writeString8(packageName);
+ data.writeInt32(mode);
+ data.writeString16(opPackageName);
remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
}
+
+ virtual int isDataInjectionEnabled() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ remote()->transact(ENABLE_DATA_INJECTION, data, &reply);
+ return reply.readInt32();
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -86,7 +99,8 @@
switch(code) {
case GET_SENSOR_LIST: {
CHECK_INTERFACE(ISensorServer, data, reply);
- Vector<Sensor> v(getSensorList());
+ const String16& opPackageName = data.readString16();
+ Vector<Sensor> v(getSensorList(opPackageName));
size_t n = v.size();
reply->writeUint32(static_cast<uint32_t>(n));
for (size_t i = 0; i < n; i++) {
@@ -96,10 +110,20 @@
}
case CREATE_SENSOR_EVENT_CONNECTION: {
CHECK_INTERFACE(ISensorServer, data, reply);
- sp<ISensorEventConnection> connection(createSensorEventConnection());
+ String8 packageName = data.readString8();
+ int32_t mode = data.readInt32();
+ const String16& opPackageName = data.readString16();
+ sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode,
+ opPackageName));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
+ case ENABLE_DATA_INJECTION: {
+ CHECK_INTERFACE(ISensorServer, data, reply);
+ int32_t ret = isDataInjectionEnabled();
+ reply->writeInt32(static_cast<int32_t>(ret));
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 35661f2..2545eec 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -25,6 +25,9 @@
#include <hardware/sensors.h>
+#include <binder/AppOpsManager.h>
+#include <binder/IServiceManager.h>
+
#include <gui/Sensor.h>
#include <log/log.h>
@@ -113,11 +116,13 @@
mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
break;
- case SENSOR_TYPE_HEART_RATE:
+ case SENSOR_TYPE_HEART_RATE: {
mStringType = SENSOR_STRING_TYPE_HEART_RATE;
mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
+ AppOpsManager appOps;
+ mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
- break;
+ } break;
case SENSOR_TYPE_LIGHT:
mStringType = SENSOR_STRING_TYPE_LIGHT;
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
@@ -252,6 +257,17 @@
}
}
+
+ if (mRequiredPermission.length() > 0) {
+ // If the sensor is protected by a permission we need to know if it is
+ // a runtime one to determine whether we can use the permission cache.
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+ if (binder != 0) {
+ sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+ mRequiredPermissionRuntime = permCtrl->isRuntimePermission(
+ String16(mRequiredPermission));
+ }
+ }
}
Sensor::~Sensor()
@@ -318,6 +334,14 @@
return mRequiredPermission;
}
+bool Sensor::isRequiredPermissionRuntime() const {
+ return mRequiredPermissionRuntime;
+}
+
+int32_t Sensor::getRequiredAppOp() const {
+ return mRequiredAppOp;
+}
+
int32_t Sensor::getMaxDelay() const {
return mMaxDelay;
}
@@ -339,7 +363,8 @@
size_t fixedSize =
sizeof(int32_t) * 3 +
sizeof(float) * 4 +
- sizeof(int32_t) * 5;
+ sizeof(int32_t) * 6 +
+ sizeof(bool);
size_t variableSize =
sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) +
@@ -369,6 +394,8 @@
FlattenableUtils::write(buffer, size, mFifoMaxEventCount);
flattenString8(buffer, size, mStringType);
flattenString8(buffer, size, mRequiredPermission);
+ FlattenableUtils::write(buffer, size, mRequiredPermissionRuntime);
+ FlattenableUtils::write(buffer, size, mRequiredAppOp);
FlattenableUtils::write(buffer, size, mMaxDelay);
FlattenableUtils::write(buffer, size, mFlags);
return NO_ERROR;
@@ -407,6 +434,8 @@
if (!unflattenString8(buffer, size, mRequiredPermission)) {
return NO_MEMORY;
}
+ FlattenableUtils::read(buffer, size, mRequiredPermissionRuntime);
+ FlattenableUtils::read(buffer, size, mRequiredAppOp);
FlattenableUtils::read(buffer, size, mMaxDelay);
FlattenableUtils::read(buffer, size, mFlags);
return NO_ERROR;
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 76ae470..4b7986e 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <linux/errno.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -149,6 +150,23 @@
return mSensorEventConnection->setEventRate(sensor->getHandle(), ns);
}
+status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) {
+ do {
+ // Blocking call.
+ ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL);
+ if (size >= 0) {
+ return NO_ERROR;
+ } else if (size < 0 && errno == EAGAIN) {
+ // If send is returning a "Try again" error, sleep for 100ms and try again. In all
+ // other cases log a failure and exit.
+ usleep(100000);
+ } else {
+ ALOGE("injectSensorEvent failure %s %zd", strerror(errno), size);
+ return INVALID_OPERATION;
+ }
+ } while (true);
+}
+
void SensorEventQueue::sendAck(const ASensorEvent* events, int count) {
for (int i = 0; i < count; ++i) {
if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) {
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index d6df404..dd37781 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -36,10 +36,8 @@
namespace android {
// ----------------------------------------------------------------------------
-ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager)
-
-SensorManager::SensorManager()
- : mSensorList(0)
+SensorManager::SensorManager(const String16& opPackageName)
+ : mSensorList(0), mOpPackageName(opPackageName)
{
// okay we're not locked here, but it's not needed during construction
assertStateLocked();
@@ -88,7 +86,7 @@
mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this));
IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);
- mSensors = mSensorServer->getSensorList();
+ mSensors = mSensorServer->getSensorList(mOpPackageName);
size_t count = mSensors.size();
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
@@ -100,8 +98,6 @@
return NO_ERROR;
}
-
-
ssize_t SensorManager::getSensorList(Sensor const* const** list) const
{
Mutex::Autolock _l(mLock);
@@ -139,18 +135,17 @@
return NULL;
}
-sp<SensorEventQueue> SensorManager::createEventQueue()
-{
+sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
sp<SensorEventQueue> queue;
Mutex::Autolock _l(mLock);
while (assertStateLocked() == NO_ERROR) {
sp<ISensorEventConnection> connection =
- mSensorServer->createSensorEventConnection();
+ mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
if (connection == NULL) {
- // SensorService just died.
- ALOGE("createEventQueue: connection is NULL. SensorService died.");
- continue;
+ // SensorService just died or the app doesn't have required permissions.
+ ALOGE("createEventQueue: connection is NULL.");
+ return NULL;
}
queue = new SensorEventQueue(connection);
break;
@@ -158,5 +153,13 @@
return queue;
}
+bool SensorManager::isDataInjectionEnabled() {
+ Mutex::Autolock _l(mLock);
+ if (assertStateLocked() == NO_ERROR) {
+ return mSensorServer->isDataInjectionEnabled();
+ }
+ return false;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index df0661c..4b76f98 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -344,20 +344,61 @@
if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
input.setSurfaceDamage(Region::INVALID_REGION);
} else {
- // The surface damage was specified using the OpenGL ES convention of
- // the origin being in the bottom-left corner. Here we flip to the
- // convention that the rest of the system uses (top-left corner) by
- // subtracting all top/bottom coordinates from the buffer height.
+ // Here we do two things:
+ // 1) The surface damage was specified using the OpenGL ES convention of
+ // the origin being in the bottom-left corner. Here we flip to the
+ // convention that the rest of the system uses (top-left corner) by
+ // subtracting all top/bottom coordinates from the buffer height.
+ // 2) If the buffer is coming in rotated (for example, because the EGL
+ // implementation is reacting to the transform hint coming back from
+ // SurfaceFlinger), the surface damage needs to be rotated the
+ // opposite direction, since it was generated assuming an unrotated
+ // buffer (the app doesn't know that the EGL implementation is
+ // reacting to the transform hint behind its back). The
+ // transformations in the switch statement below apply those
+ // complementary rotations (e.g., if 90 degrees, rotate 270 degrees).
+
+ int width = buffer->width;
int height = buffer->height;
- if ((mTransform ^ mStickyTransform) & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- height = buffer->width;
+ bool rotated90 = (mTransform ^ mStickyTransform) &
+ NATIVE_WINDOW_TRANSFORM_ROT_90;
+ if (rotated90) {
+ std::swap(width, height);
}
+
Region flippedRegion;
for (auto rect : mDirtyRegion) {
- auto top = height - rect.bottom;
- auto bottom = height - rect.top;
- Rect flippedRect{rect.left, top, rect.right, bottom};
- flippedRegion.orSelf(flippedRect);
+ int left = rect.left;
+ int right = rect.right;
+ int top = height - rect.bottom; // Flip from OpenGL convention
+ int bottom = height - rect.top; // Flip from OpenGL convention
+ switch (mTransform ^ mStickyTransform) {
+ case NATIVE_WINDOW_TRANSFORM_ROT_90: {
+ // Rotate 270 degrees
+ Rect flippedRect{top, width - right, bottom, width - left};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ case NATIVE_WINDOW_TRANSFORM_ROT_180: {
+ // Rotate 180 degrees
+ Rect flippedRect{width - right, height - bottom,
+ width - left, height - top};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ case NATIVE_WINDOW_TRANSFORM_ROT_270: {
+ // Rotate 90 degrees
+ Rect flippedRect{height - bottom, left,
+ height - top, right};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ default: {
+ Rect flippedRect{left, top, right, bottom};
+ flippedRegion.orSelf(flippedRect);
+ break;
+ }
+ }
}
input.setSurfaceDamage(flippedRegion);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 707a321..6ad47d8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -310,11 +310,10 @@
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- if (mask & layer_state_t::eLayerOpaque) {
- s->what |= layer_state_t::eOpacityChanged;
- }
- if (mask & layer_state_t::eLayerHidden) {
- s->what |= layer_state_t::eVisibilityChanged;
+ if (mask & layer_state_t::eLayerOpaque ||
+ mask & layer_state_t::eLayerHidden ||
+ mask & layer_state_t::eLayerSecure) {
+ s->what |= layer_state_t::eFlagsChanged;
}
s->flags &= ~mask;
s->flags |= (flags & mask);
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index f1921a4..944ac7f 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -27,6 +27,7 @@
deviceSources := \
$(commonSources) \
+ IInputFlinger.cpp \
InputTransport.cpp \
VelocityControl.cpp \
VelocityTracker.cpp
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
new file mode 100644
index 0000000..e009731
--- /dev/null
+++ b/libs/input/IInputFlinger.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 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 <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <input/IInputFlinger.h>
+
+
+namespace android {
+
+class BpInputFlinger : public BpInterface<IInputFlinger> {
+public:
+ BpInputFlinger(const sp<IBinder>& impl) :
+ BpInterface<IInputFlinger>(impl) { }
+
+ virtual status_t doSomething() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+ remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
+
+
+status_t BnInputFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ switch(code) {
+ case DO_SOMETHING_TRANSACTION: {
+ CHECK_INTERFACE(IInputFlinger, data, reply);
+ reply->writeInt32(0);
+ break;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ return NO_ERROR;
+}
+
+};
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 69a6432..88cd653 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -216,6 +216,7 @@
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t actionButton,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
@@ -231,6 +232,7 @@
const PointerCoords* pointerCoords) {
InputEvent::initialize(deviceId, source);
mAction = action;
+ mActionButton = actionButton;
mFlags = flags;
mEdgeFlags = edgeFlags;
mMetaState = metaState;
@@ -250,6 +252,7 @@
void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
InputEvent::initialize(other->mDeviceId, other->mSource);
mAction = other->mAction;
+ mActionButton = other->mActionButton;
mFlags = other->mFlags;
mEdgeFlags = other->mEdgeFlags;
mMetaState = other->mMetaState;
@@ -428,6 +431,7 @@
mDeviceId = parcel->readInt32();
mSource = parcel->readInt32();
mAction = parcel->readInt32();
+ mActionButton = parcel->readInt32();
mFlags = parcel->readInt32();
mEdgeFlags = parcel->readInt32();
mMetaState = parcel->readInt32();
@@ -475,6 +479,7 @@
parcel->writeInt32(mDeviceId);
parcel->writeInt32(mSource);
parcel->writeInt32(mAction);
+ parcel->writeInt32(mActionButton);
parcel->writeInt32(mFlags);
parcel->writeInt32(mEdgeFlags);
parcel->writeInt32(mMetaState);
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index b11110a..d755ed3 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -127,28 +127,31 @@
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
- initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false);
+ initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
}
InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber),
mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal),
- mSources(other.mSources), mKeyboardType(other.mKeyboardType),
- mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator),
- mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) {
+ mHasMic(other.mHasMic), mSources(other.mSources),
+ mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap),
+ mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad),
+ mMotionRanges(other.mMotionRanges) {
}
InputDeviceInfo::~InputDeviceInfo() {
}
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) {
+ const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+ bool hasMic) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
mIdentifier = identifier;
mAlias = alias;
mIsExternal = isExternal;
+ mHasMic = hasMic;
mSources = 0;
mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
mHasVibrator = false;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 090ee53..0382f57 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -283,6 +283,7 @@
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t actionButton,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
@@ -298,12 +299,12 @@
const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
- "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
- "xOffset=%f, yOffset=%f, "
+ "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
+ "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
"pointerCount=%" PRIu32,
mChannel->getName().string(), seq,
- deviceId, source, action, flags, edgeFlags, metaState, buttonState,
+ deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif
@@ -324,6 +325,7 @@
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.action = action;
+ msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
@@ -907,6 +909,7 @@
msg->body.motion.deviceId,
msg->body.motion.source,
msg->body.motion.action,
+ msg->body.motion.actionButton,
msg->body.motion.flags,
msg->body.motion.edgeFlags,
msg->body.motion.metaState,
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 9105ae5..3fb1c6d 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -248,7 +248,7 @@
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
- event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+ event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0,
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
@@ -557,7 +557,7 @@
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
}
MotionEvent event;
- event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0,
+ event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
float originalRawX = 0 + 3;
float originalRawY = -RADIUS + 2;
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index de192f1..8e69c9c 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -133,6 +133,7 @@
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
const int32_t action = AMOTION_EVENT_ACTION_MOVE;
+ const int32_t actionButton = 0;
const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
@@ -163,8 +164,8 @@
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
}
- status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags,
- metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
+ status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton,
+ flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
downTime, eventTime, pointerCount,
pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
@@ -255,7 +256,7 @@
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -271,7 +272,7 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 83bc6ae..8d73f45 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -51,10 +51,11 @@
CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
CHECK_OFFSET(InputMessage::Body::Motion, action, 24);
- CHECK_OFFSET(InputMessage::Body::Motion, flags, 28);
- CHECK_OFFSET(InputMessage::Body::Motion, metaState, 32);
- CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 36);
- CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 40);
+ CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28);
+ CHECK_OFFSET(InputMessage::Body::Motion, flags, 32);
+ CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36);
+ CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40);
+ CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44);
CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48);
CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56);
CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60);
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index cc9b50c..18ad300 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -59,11 +59,6 @@
LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE)
endif
-ifeq (address, $(strip $(SANITIZE_TARGET)))
- LOCAL_CFLAGS_32 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib\"
- LOCAL_CFLAGS_64 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib64\"
-endif
-
LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module)
egl.cfg_config_module :=
@@ -91,6 +86,9 @@
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
+
include $(BUILD_SHARED_LIBRARY)
@@ -116,6 +114,9 @@
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
+
# Symlink libGLESv3.so -> libGLESv2.so
# Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
# will be linked against libGLESv3.so.
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 8df9af3..1fcc048 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -167,14 +167,6 @@
return so;
}
-#ifndef EGL_WRAPPER_DIR
-#if defined(__LP64__)
-#define EGL_WRAPPER_DIR "/system/lib64"
-#else
-#define EGL_WRAPPER_DIR "/system/lib"
-#endif
-#endif
-
void* Loader::open(egl_connection_t* cnx)
{
void* dso;
@@ -195,10 +187,15 @@
LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
- cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
- cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
- cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
-
+#if defined(__LP64__)
+ cnx->libEgl = load_wrapper("/system/lib64/libEGL.so");
+ cnx->libGles2 = load_wrapper("/system/lib64/libGLESv2.so");
+ cnx->libGles1 = load_wrapper("/system/lib64/libGLESv1_CM.so");
+#else
+ cnx->libEgl = load_wrapper("/system/lib/libEGL.so");
+ cnx->libGles2 = load_wrapper("/system/lib/libGLESv2.so");
+ cnx->libGles1 = load_wrapper("/system/lib/libGLESv1_CM.so");
+#endif
LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
"couldn't load system EGL wrapper libraries");
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 8dd052c..8378907 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -91,11 +91,19 @@
"EGL_KHR_gl_colorspace "
#endif
"EGL_KHR_gl_texture_2D_image "
+ "EGL_KHR_gl_texture_3D_image "
"EGL_KHR_gl_texture_cubemap_image "
"EGL_KHR_gl_renderbuffer_image "
"EGL_KHR_reusable_sync "
"EGL_KHR_fence_sync "
"EGL_KHR_create_context "
+ "EGL_KHR_config_attribs "
+ "EGL_KHR_surfaceless_context "
+ "EGL_KHR_stream "
+ "EGL_KHR_stream_fifo "
+ "EGL_KHR_stream_producer_eglsurface "
+ "EGL_KHR_stream_consumer_gltexture "
+ "EGL_KHR_stream_cross_process_fd "
"EGL_EXT_create_context_robustness "
"EGL_NV_system_time "
"EGL_ANDROID_image_native_buffer " // mandatory
@@ -164,6 +172,31 @@
// EGL_KHR_partial_update
{ "eglSetDamageRegionKHR",
(__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR },
+
+ { "eglCreateStreamKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR },
+ { "eglDestroyStreamKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR },
+ { "eglStreamAttribKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR },
+ { "eglQueryStreamKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR },
+ { "eglQueryStreamu64KHR",
+ (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR },
+ { "eglQueryStreamTimeKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR },
+ { "eglCreateStreamProducerSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR },
+ { "eglStreamConsumerGLTextureExternalKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR },
+ { "eglStreamConsumerAcquireKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR },
+ { "eglStreamConsumerReleaseKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR },
+ { "eglGetStreamFileDescriptorKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR },
+ { "eglCreateStreamFromFileDescriptorKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
};
/*
@@ -1527,6 +1560,212 @@
return result;
}
+EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_STREAM_KHR;
+
+ EGLStreamKHR result = EGL_NO_STREAM_KHR;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglCreateStreamKHR) {
+ result = cnx->egl.eglCreateStreamKHR(
+ dp->disp.dpy, attrib_list);
+ }
+ return result;
+}
+
+EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglDestroyStreamKHR) {
+ result = cnx->egl.eglDestroyStreamKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
+}
+
+EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLint value)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglStreamAttribKHR) {
+ result = cnx->egl.eglStreamAttribKHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
+}
+
+EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLint *value)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglQueryStreamKHR) {
+ result = cnx->egl.eglQueryStreamKHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
+}
+
+EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLuint64KHR *value)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) {
+ result = cnx->egl.eglQueryStreamu64KHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
+}
+
+EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLTimeKHR *value)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) {
+ result = cnx->egl.eglQueryStreamTimeKHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
+}
+
+EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config,
+ EGLStreamKHR stream, const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_SURFACE;
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) {
+ EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
+ dp->disp.dpy, config, stream, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
+ surface, cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy,
+ EGLStreamKHR stream)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) {
+ result = cnx->egl.eglStreamConsumerGLTextureExternalKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
+}
+
+EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy,
+ EGLStreamKHR stream)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) {
+ result = cnx->egl.eglStreamConsumerAcquireKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
+}
+
+EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy,
+ EGLStreamKHR stream)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) {
+ result = cnx->egl.eglStreamConsumerReleaseKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
+}
+
+EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(
+ EGLDisplay dpy, EGLStreamKHR stream)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR;
+
+ EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) {
+ result = cnx->egl.eglGetStreamFileDescriptorKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
+}
+
+EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(
+ EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_STREAM_KHR;
+
+ EGLStreamKHR result = EGL_NO_STREAM_KHR;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) {
+ result = cnx->egl.eglCreateStreamFromFileDescriptorKHR(
+ dp->disp.dpy, file_descriptor);
+ }
+ return result;
+}
+
// ----------------------------------------------------------------------------
// EGL_EGLEXT_VERSION 15
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 1e27cb6..498b2fc 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -61,18 +61,18 @@
/* EGL_EGLEXT_VERSION 15 */
-// EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR, EGLDisplay, const EGLint *)
-// EGL_ENTRY(EGLBoolean, eglDestroyStreamKHR, EGLDisplay, EGLStreamKHR)
-// EGL_ENTRY(EGLBoolean, eglStreamAttribKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint)
-// EGL_ENTRY(EGLBoolean, eglQueryStreamKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint *)
-// EGL_ENTRY(EGLBoolean, eglQueryStreamu64KHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR *)
-// EGL_ENTRY(EGLBoolean, eglStreamConsumerGLTextureExternalKHR, EGLDisplay, EGLStreamKHR)
-// EGL_ENTRY(EGLBoolean, eglStreamConsumerAcquireKHR, EGLDisplay, EGLStreamKHR)
-// EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR)
-// EGL_ENTRY(EGLSurface, eglCreateStreamProducerSurfaceKHR, EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint *)
-// EGL_ENTRY(EGLBoolean, eglQueryStreamTimeKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*)
-// EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR)
-// EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR)
+EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR, EGLDisplay, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyStreamKHR, EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLBoolean, eglStreamAttribKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint)
+EGL_ENTRY(EGLBoolean, eglQueryStreamKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint *)
+EGL_ENTRY(EGLBoolean, eglQueryStreamu64KHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR *)
+EGL_ENTRY(EGLBoolean, eglStreamConsumerGLTextureExternalKHR, EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLBoolean, eglStreamConsumerAcquireKHR, EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLSurface, eglCreateStreamProducerSurfaceKHR, EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglQueryStreamTimeKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*)
+EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR)
EGL_ENTRY(EGLint, eglWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint)
/* ANDROID extensions */
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index d511940..918faa8 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -14,6 +14,9 @@
** limitations under the License.
*/
+#include <string>
+#include <sstream>
+
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
@@ -115,15 +118,11 @@
}
// tokenize the supported extensions for the glGetStringi() wrapper
- exts = gl_extensions.string();
- while (1) {
- const char *end = strchr(exts, ' ');
- if (end == NULL) {
- tokenized_gl_extensions.push(String8(exts));
- break;
- }
- tokenized_gl_extensions.push(String8(exts, end - exts));
- exts = end + 1;
+ std::stringstream ss;
+ std::string str;
+ ss << gl_extensions.string();
+ while (ss >> str) {
+ tokenized_gl_extensions.push(String8(str.c_str()));
}
}
}
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
index 1af59a3..ed867d8 100644
--- a/services/inputflinger/Android.mk
+++ b/services/inputflinger/Android.mk
@@ -45,3 +45,5 @@
LOCAL_MODULE := libinputflinger
include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 93ce010..6b60c7c 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -131,6 +131,13 @@
}
}
+ // External stylus gets the pressure axis
+ if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ if (axis == ABS_PRESSURE) {
+ return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+ }
+ }
+
// Joystick devices get the rest.
return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK;
}
@@ -1185,6 +1192,16 @@
&& test_bit(ABS_X, device->absBitmask)
&& test_bit(ABS_Y, device->absBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
+ // Is this a BT stylus?
+ } else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
+ test_bit(BTN_TOUCH, device->keyBitmask))
+ && !test_bit(ABS_X, device->absBitmask)
+ && !test_bit(ABS_Y, device->absBitmask)) {
+ device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+ // Keyboard will try to claim some of the buttons but we really want to reserve those so we
+ // can fuse it with the touch screen data, so just take them back. Note this means an
+ // external stylus cannot also be a keyboard device.
+ device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;
}
// See if this device is a joystick.
@@ -1279,6 +1296,11 @@
return -1;
}
+ // Determine whether the device has a mic.
+ if (deviceHasMicLocked(device)) {
+ device->classes |= INPUT_DEVICE_CLASS_MIC;
+ }
+
// Determine whether the device is external or internal.
if (isExternalDeviceLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
@@ -1293,7 +1315,10 @@
// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
- eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
+ eventItem.events = EPOLLIN;
+ if (mUsingEpollWakeup) {
+ eventItem.events |= EPOLLWAKEUP;
+ }
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
@@ -1412,6 +1437,16 @@
return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
}
+bool EventHub::deviceHasMicLocked(Device* device) {
+ if (device->configuration) {
+ bool value;
+ if (device->configuration->tryGetProperty(String8("audio.mic"), value)) {
+ return value;
+ }
+ }
+ return false;
+}
+
int32_t EventHub::getNextControllerNumberLocked(Device* device) {
if (mControllerNumbers.isFull()) {
ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 20179ae..3ec4910 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -131,6 +131,12 @@
/* The input device has a vibrator (supports FF_RUMBLE). */
INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200,
+ /* The input device has a microphone. */
+ INPUT_DEVICE_CLASS_MIC = 0x00000400,
+
+ /* The input device is an external stylus (has data we want to fuse with touch data). */
+ INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,
+
/* The input device is virtual (not a real device, not part of UI configuration). */
INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000,
@@ -394,6 +400,7 @@
status_t loadKeyMapLocked(Device* device);
bool isExternalDeviceLocked(Device* device);
+ bool deviceHasMicLocked(Device* device);
int32_t getNextControllerNumberLocked(Device* device);
void releaseControllerNumberLocked(Device* device);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 9157bc1..0fba1bf 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -119,7 +119,7 @@
return true;
}
-static bool isValidMotionAction(int32_t action, size_t pointerCount) {
+static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
@@ -136,14 +136,17 @@
int32_t index = getMotionEventActionPointerIndex(action);
return index >= 0 && size_t(index) < pointerCount;
}
+ case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
+ return actionButton != 0;
default:
return false;
}
}
-static bool validateMotionEvent(int32_t action, size_t pointerCount,
+static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
const PointerProperties* pointerProperties) {
- if (! isValidMotionAction(action, pointerCount)) {
+ if (! isValidMotionAction(action, actionButton, pointerCount)) {
ALOGE("Motion event has invalid action code 0x%x", action);
return false;
}
@@ -198,7 +201,8 @@
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
- mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
+ mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
+ mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
@@ -394,6 +398,7 @@
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
+ mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
@@ -503,7 +508,9 @@
reason = "inbound event was dropped because the policy consumed it";
break;
case DROP_REASON_DISABLED:
- ALOGI("Dropped event because input dispatch is disabled.");
+ if (mLastDropReason != DROP_REASON_DISABLED) {
+ ALOGI("Dropped event because input dispatch is disabled.");
+ }
reason = "inbound event was dropped because input dispatch is disabled";
break;
case DROP_REASON_APP_SWITCH:
@@ -852,6 +859,13 @@
setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+ if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
+ CancelationOptions::Mode mode(isPointerEvent ?
+ CancelationOptions::CANCEL_POINTER_EVENTS :
+ CancelationOptions::CANCEL_NON_POINTER_EVENTS);
+ CancelationOptions options(mode, "input event injection failed");
+ synthesizeCancelationEventsForMonitorsLocked(options);
+ }
return true;
}
@@ -874,12 +888,12 @@
void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
- "action=0x%x, flags=0x%x, "
- "metaState=0x%x, buttonState=0x%x, "
+ "action=0x%x, actionButton=0x%x, flags=0x%x, "
+ "metaState=0x%x, buttonState=0x%x,"
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
prefix,
entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
- entry->action, entry->flags,
+ entry->action, entry->actionButton, entry->flags,
entry->metaState, entry->buttonState,
entry->edgeFlags, entry->xPrecision, entry->yPrecision,
entry->downTime);
@@ -1981,10 +1995,10 @@
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
- motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
- xOffset, yOffset,
- motionEntry->xPrecision, motionEntry->yPrecision,
+ dispatchEntry->resolvedAction, motionEntry->actionButton,
+ dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
+ motionEntry->metaState, motionEntry->buttonState,
+ xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
@@ -2160,6 +2174,13 @@
}
}
+void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
+ const CancelationOptions& options) {
+ for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+ synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options);
+ }
+}
+
void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
const sp<InputChannel>& channel, const CancelationOptions& options) {
ssize_t index = getConnectionIndexLocked(channel);
@@ -2298,6 +2319,7 @@
originalMotionEntry->source,
originalMotionEntry->policyFlags,
action,
+ originalMotionEntry->actionButton,
originalMotionEntry->flags,
originalMotionEntry->metaState,
originalMotionEntry->buttonState,
@@ -2432,10 +2454,10 @@
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
- "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, "
- "xPrecision=%f, yPrecision=%f, downTime=%lld",
+ "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
args->eventTime, args->deviceId, args->source, args->policyFlags,
- args->action, args->flags, args->metaState, args->buttonState,
+ args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
for (uint32_t i = 0; i < args->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
@@ -2455,7 +2477,8 @@
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
}
#endif
- if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) {
+ if (!validateMotionEvent(args->action, args->actionButton,
+ args->pointerCount, args->pointerProperties)) {
return;
}
@@ -2471,9 +2494,9 @@
mLock.unlock();
MotionEvent event;
- event.initialize(args->deviceId, args->source, args->action, args->flags,
- args->edgeFlags, args->metaState, args->buttonState, 0, 0,
- args->xPrecision, args->yPrecision,
+ event.initialize(args->deviceId, args->source, args->action, args->actionButton,
+ args->flags, args->edgeFlags, args->metaState, args->buttonState,
+ 0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
@@ -2488,7 +2511,8 @@
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
- args->action, args->flags, args->metaState, args->buttonState,
+ args->action, args->actionButton, args->flags,
+ args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
@@ -2589,7 +2613,8 @@
int32_t action = motionEvent->getAction();
size_t pointerCount = motionEvent->getPointerCount();
const PointerProperties* pointerProperties = motionEvent->getPointerProperties();
- if (! validateMotionEvent(action, pointerCount, pointerProperties)) {
+ int32_t actionButton = motionEvent->getActionButton();
+ if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
return INPUT_EVENT_INJECTION_FAILED;
}
@@ -2603,7 +2628,7 @@
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
firstInjectedEntry = new MotionEntry(*sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
- action, motionEvent->getFlags(),
+ action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
@@ -2616,7 +2641,7 @@
samplePointerCoords += pointerCount;
MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
- action, motionEvent->getFlags(),
+ action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
@@ -3907,18 +3932,18 @@
// --- InputDispatcher::MotionEntry ---
-InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
- int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
- int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, float xPrecision, float yPrecision,
- nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
+InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId,
+ uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+ float xPrecision, float yPrecision, nsecs_t downTime,
+ int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset) :
EventEntry(TYPE_MOTION, eventTime, policyFlags),
eventTime(eventTime),
- deviceId(deviceId), source(source), action(action), flags(flags),
- metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
- xPrecision(xPrecision), yPrecision(yPrecision),
+ deviceId(deviceId), source(source), action(action), actionButton(actionButton),
+ flags(flags), metaState(metaState), buttonState(buttonState),
+ edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision),
downTime(downTime), displayId(displayId), pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -3933,10 +3958,10 @@
}
void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
- msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, "
- "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, "
- "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
- deviceId, source, action, flags, metaState, buttonState, edgeFlags,
+ msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
+ "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
+ "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
+ deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags,
xPrecision, yPrecision, displayId);
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
@@ -4237,7 +4262,7 @@
memento.hovering
? AMOTION_EVENT_ACTION_HOVER_EXIT
: AMOTION_EVENT_ACTION_CANCEL,
- memento.flags, 0, 0, 0,
+ memento.flags, 0, 0, 0, 0,
memento.xPrecision, memento.yPrecision, memento.downTime,
memento.displayId,
memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 8c78a44..98355c6 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -504,6 +504,7 @@
int32_t deviceId;
uint32_t source;
int32_t action;
+ int32_t actionButton;
int32_t flags;
int32_t metaState;
int32_t buttonState;
@@ -518,10 +519,10 @@
MotionEntry(nsecs_t eventTime,
int32_t deviceId, uint32_t source, uint32_t policyFlags,
- int32_t action, int32_t flags,
+ int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- float xPrecision, float yPrecision,
- nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
+ float xPrecision, float yPrecision, nsecs_t downTime,
+ int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset);
virtual void appendDescription(String8& msg) const;
@@ -856,6 +857,8 @@
Queue<EventEntry> mRecentQueue;
Queue<CommandEntry> mCommandQueue;
+ DropReason mLastDropReason;
+
void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
@@ -1073,6 +1076,7 @@
void synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options);
+ void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options);
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
const CancelationOptions& options);
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 85bb0ed..dded47d 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -68,12 +68,13 @@
NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
+ int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
+ int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) :
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
- action(action), flags(flags), metaState(metaState), buttonState(buttonState),
+ action(action), actionButton(actionButton),
+ flags(flags), metaState(metaState), buttonState(buttonState),
edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount),
xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
@@ -85,10 +86,9 @@
NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
policyFlags(other.policyFlags),
- action(other.action), flags(other.flags),
+ action(other.action), actionButton(other.actionButton), flags(other.flags),
metaState(other.metaState), buttonState(other.buttonState),
- edgeFlags(other.edgeFlags), displayId(other.displayId),
- pointerCount(other.pointerCount),
+ edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount),
xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
pointerProperties[i].copyFrom(other.pointerProperties[i]);
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index 78ae10f..1ec09ce 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -84,6 +84,7 @@
uint32_t source;
uint32_t policyFlags;
int32_t action;
+ int32_t actionButton;
int32_t flags;
int32_t metaState;
int32_t buttonState;
@@ -99,7 +100,8 @@
inline NotifyMotionArgs() { }
NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
+ int32_t action, int32_t actionButton, int32_t flags,
+ int32_t metaState, int32_t buttonState,
int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 318c85f..bd74b02 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -39,12 +39,16 @@
// Log debug messages about the vibrator.
#define DEBUG_VIBRATOR 0
+// Log debug messages about fusing stylus data.
+#define DEBUG_STYLUS_FUSION 0
+
#include "InputReader.h"
#include <cutils/log.h>
#include <input/Keyboard.h>
#include <input/VirtualKeyMap.h>
+#include <inttypes.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
@@ -65,6 +69,17 @@
// Maximum number of slots supported when using the slot-based Multitouch Protocol B.
static const size_t MAX_SLOTS = 32;
+// Maximum amount of latency to add to touch events while waiting for data from an
+// external stylus.
+static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
+
+// Maximum amount of time to wait on touch data before pushing out new pressure data.
+static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
+
+// Artificial latency on synthetic events created from stylus data without corresponding touch
+// data.
+static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+
// --- Static Functions ---
template<typename T>
@@ -381,6 +396,10 @@
mDevices.add(deviceId, device);
bumpGenerationLocked();
+
+ if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ notifyExternalStylusPresenceChanged();
+ }
}
void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
@@ -403,6 +422,10 @@
device->getId(), device->getName().string(), device->getSources());
}
+ if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ notifyExternalStylusPresenceChanged();
+ }
+
device->reset(when);
delete device;
}
@@ -417,6 +440,11 @@
device->setExternal(true);
}
+ // Devices with mics.
+ if (classes & INPUT_DEVICE_CLASS_MIC) {
+ device->setMic(true);
+ }
+
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device));
@@ -464,6 +492,11 @@
device->addMapper(new JoystickInputMapper(device));
}
+ // External stylus-like devices.
+ if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ device->addMapper(new ExternalStylusInputMapper(device));
+ }
+
return device;
}
@@ -534,6 +567,27 @@
return mGlobalMetaState;
}
+void InputReader::notifyExternalStylusPresenceChanged() {
+ refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
+}
+
+void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) {
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) {
+ outDevices.push();
+ device->getDeviceInfo(&outDevices.editTop());
+ }
+ }
+}
+
+void InputReader::dispatchExternalStylusState(const StylusState& state) {
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ device->updateExternalStylusState(state);
+ }
+}
+
void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) {
mDisableVirtualKeysTimeout = time;
}
@@ -824,6 +878,15 @@
return mReader->bumpGenerationLocked();
}
+void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+ // lock is already held by whatever called refreshConfigurationLocked
+ mReader->getExternalStylusDevicesLocked(outDevices);
+}
+
+void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) {
+ mReader->dispatchExternalStylusState(state);
+}
+
InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
return mReader->mPolicy.get();
}
@@ -858,7 +921,7 @@
int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) :
mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber),
mIdentifier(identifier), mClasses(classes),
- mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
+ mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) {
}
InputDevice::~InputDevice() {
@@ -877,6 +940,7 @@
deviceInfo.getDisplayName().string());
dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
+ dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic));
dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
@@ -1006,10 +1070,17 @@
}
}
+void InputDevice::updateExternalStylusState(const StylusState& state) {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->updateExternalStylusState(state);
+ }
+}
+
void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
- mIsExternal);
-
+ mIsExternal, mHasMic);
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
@@ -1078,6 +1149,14 @@
}
}
+void InputDevice::cancelTouch(nsecs_t when) {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->cancelTouch(when);
+ }
+}
+
int32_t InputDevice::getMetaState() {
int32_t result = 0;
size_t numMappers = mMappers.size();
@@ -1277,7 +1356,9 @@
void TouchButtonAccumulator::reset(InputDevice* device) {
mBtnTouch = device->isKeyPressed(BTN_TOUCH);
mBtnStylus = device->isKeyPressed(BTN_STYLUS);
- mBtnStylus2 = device->isKeyPressed(BTN_STYLUS);
+ // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
+ mBtnStylus2 =
+ device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0);
mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER);
mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN);
mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER);
@@ -1318,6 +1399,7 @@
mBtnStylus = rawEvent->value;
break;
case BTN_STYLUS2:
+ case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
mBtnStylus2 = rawEvent->value;
break;
case BTN_TOOL_FINGER:
@@ -1360,10 +1442,10 @@
uint32_t TouchButtonAccumulator::getButtonState() const {
uint32_t result = 0;
if (mBtnStylus) {
- result |= AMOTION_EVENT_BUTTON_SECONDARY;
+ result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY;
}
if (mBtnStylus2) {
- result |= AMOTION_EVENT_BUTTON_TERTIARY;
+ result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY;
}
return result;
}
@@ -1786,10 +1868,17 @@
void InputMapper::cancelVibrate(int32_t token) {
}
+void InputMapper::cancelTouch(nsecs_t when) {
+}
+
int32_t InputMapper::getMetaState() {
return 0;
}
+void InputMapper::updateExternalStylusState(const StylusState& state) {
+
+}
+
void InputMapper::fadePointer() {
}
@@ -1811,6 +1900,12 @@
}
}
+void InputMapper::dumpStylusState(String8& dump, const StylusState& state) {
+ dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when);
+ dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure);
+ dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons);
+ dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
+}
// --- SwitchInputMapper ---
@@ -2134,6 +2229,9 @@
getDevice(), keyCode, scanCode)) {
return;
}
+ if (policyFlags & POLICY_FLAG_GESTURE) {
+ mDevice->cancelTouch(when);
+ }
mKeyDowns.push();
KeyDown& keyDown = mKeyDowns.editTop();
@@ -2449,7 +2547,8 @@
}
nsecs_t downTime = mDownTime;
bool buttonsChanged = currentButtonState != lastButtonState;
- bool buttonsPressed = currentButtonState & ~lastButtonState;
+ int32_t buttonsPressed = currentButtonState & ~lastButtonState;
+ int32_t buttonsReleased = lastButtonState & ~currentButtonState;
float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
@@ -2525,6 +2624,7 @@
// Send motion event.
if (downChanged || moved || scrolled || buttonsChanged) {
int32_t metaState = mContext->getGlobalMetaState();
+ int32_t buttonState = lastButtonState;
int32_t motionEventAction;
if (downChanged) {
motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
@@ -2534,17 +2634,48 @@
motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
}
+ if (buttonsReleased) {
+ BitSet32 released(buttonsReleased);
+ while (!released.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
+ buttonState &= ~actionButton;
+ NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ displayId, 1, &pointerProperties, &pointerCoords,
+ mXPrecision, mYPrecision, downTime);
+ getListener()->notifyMotion(&releaseArgs);
+ }
+ }
+
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- motionEventAction, 0, metaState, currentButtonState, 0,
+ motionEventAction, 0, 0, metaState, currentButtonState,
+ AMOTION_EVENT_EDGE_FLAG_NONE,
displayId, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&args);
+ if (buttonsPressed) {
+ BitSet32 pressed(buttonsPressed);
+ while (!pressed.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
+ buttonState |= actionButton;
+ NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ displayId, 1, &pointerProperties, &pointerCoords,
+ mXPrecision, mYPrecision, downTime);
+ getListener()->notifyMotion(&pressArgs);
+ }
+ }
+
+ ALOG_ASSERT(buttonState == currentButtonState);
+
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP
&& mPointerController != NULL) {
NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
displayId, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
@@ -2557,7 +2688,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState,
+ AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
displayId, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
@@ -2689,12 +2820,11 @@
dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
- dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState);
-
+ dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
- mLastRawPointerData.pointerCount);
- for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) {
- const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i];
+ mLastRawState.rawPointerData.pointerCount);
+ for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
+ const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
"touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
"orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
@@ -2706,11 +2836,13 @@
pointer.toolType, toString(pointer.isHovering));
}
+ dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
- mLastCookedPointerData.pointerCount);
- for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) {
- const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i];
- const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i];
+ mLastCookedState.cookedPointerData.pointerCount);
+ for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
+ const PointerProperties& pointerProperties =
+ mLastCookedState.cookedPointerData.pointerProperties[i];
+ const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
"touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
"orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
@@ -2727,9 +2859,18 @@
pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
pointerProperties.toolType,
- toString(mLastCookedPointerData.isHovering(i)));
+ toString(mLastCookedState.cookedPointerData.isHovering(i)));
}
+ dump.append(INDENT3 "Stylus Fusion:\n");
+ dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n",
+ toString(mExternalStylusConnected));
+ dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
+ dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
+ mExternalStylusFusionTimeout);
+ dump.append(INDENT3 "External Stylus State:\n");
+ dumpStylusState(dump, mExternalStylusState);
+
if (mDeviceMode == DEVICE_MODE_POINTER) {
dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
@@ -2767,7 +2908,7 @@
resolveCalibration();
}
- if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) {
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {
// Update location calibration to reflect current settings
updateAffineTransformation();
}
@@ -2782,7 +2923,8 @@
bool resetNeeded = false;
if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
| InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
- | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) {
+ | InputReaderConfiguration::CHANGE_SHOW_TOUCHES
+ | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
// Configure device sources, surface dimensions, orientation and
// scaling factors.
configureSurface(when, &resetNeeded);
@@ -2795,6 +2937,16 @@
}
}
+void TouchInputMapper::resolveExternalStylusPresence() {
+ Vector<InputDeviceInfo> devices;
+ mContext->getExternalStylusDevices(devices);
+ mExternalStylusConnected = !devices.isEmpty();
+
+ if (!mExternalStylusConnected) {
+ resetExternalStylus();
+ }
+}
+
void TouchInputMapper::configureParameters() {
// Use the pointer presentation mode for devices that do not support distinct
// multitouch. The spot-based presentation relies on being able to accurately
@@ -2931,9 +3083,15 @@
dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
}
+bool TouchInputMapper::hasExternalStylus() const {
+ return mExternalStylusConnected;
+}
+
void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
int32_t oldDeviceMode = mDeviceMode;
+ resolveExternalStylusPresence();
+
// Determine device mode.
if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
&& mConfig.pointerGesturesEnabled) {
@@ -2949,6 +3107,9 @@
if (hasStylus()) {
mSource |= AINPUT_SOURCE_STYLUS;
}
+ if (hasExternalStylus()) {
+ mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
+ }
} else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
mDeviceMode = DEVICE_MODE_NAVIGATION;
@@ -3691,28 +3852,22 @@
mWheelXVelocityControl.reset();
mWheelYVelocityControl.reset();
- mCurrentRawPointerData.clear();
- mLastRawPointerData.clear();
- mCurrentCookedPointerData.clear();
- mLastCookedPointerData.clear();
- mCurrentButtonState = 0;
- mLastButtonState = 0;
- mCurrentRawVScroll = 0;
- mCurrentRawHScroll = 0;
- mCurrentFingerIdBits.clear();
- mLastFingerIdBits.clear();
- mCurrentStylusIdBits.clear();
- mLastStylusIdBits.clear();
- mCurrentMouseIdBits.clear();
- mLastMouseIdBits.clear();
+ mRawStatesPending.clear();
+ mCurrentRawState.clear();
+ mCurrentCookedState.clear();
+ mLastRawState.clear();
+ mLastCookedState.clear();
mPointerUsage = POINTER_USAGE_NONE;
mSentHoverEnter = false;
+ mHavePointerIds = false;
+ mCurrentMotionAborted = false;
mDownTime = 0;
mCurrentVirtualKey.down = false;
mPointerGesture.reset();
mPointerSimple.reset();
+ resetExternalStylus();
if (mPointerController != NULL) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -3722,6 +3877,18 @@
InputMapper::reset(when);
}
+void TouchInputMapper::resetExternalStylus() {
+ mExternalStylusState.clear();
+ mExternalStylusId = -1;
+ mExternalStylusFusionTimeout = LLONG_MAX;
+ mExternalStylusDataPending = false;
+}
+
+void TouchInputMapper::clearStylusDataPendingFlags() {
+ mExternalStylusDataPending = false;
+ mExternalStylusFusionTimeout = LLONG_MAX;
+}
+
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
@@ -3733,155 +3900,288 @@
}
void TouchInputMapper::sync(nsecs_t when) {
+ const RawState* last = mRawStatesPending.isEmpty() ?
+ &mCurrentRawState : &mRawStatesPending.top();
+
+ // Push a new state.
+ mRawStatesPending.push();
+ RawState* next = &mRawStatesPending.editTop();
+ next->clear();
+ next->when = when;
+
// Sync button state.
- mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
+ next->buttonState = mTouchButtonAccumulator.getButtonState()
| mCursorButtonAccumulator.getButtonState();
- // Sync scroll state.
- mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
- mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
+ // Sync scroll
+ next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
+ next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
- // Sync touch state.
- bool havePointerIds = true;
- mCurrentRawPointerData.clear();
- syncTouch(when, &havePointerIds);
+ // Sync touch
+ syncTouch(when, next);
+
+ // Assign pointer ids.
+ if (!mHavePointerIds) {
+ assignPointerIds(last, next);
+ }
#if DEBUG_RAW_EVENTS
- if (!havePointerIds) {
- ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids",
- mLastRawPointerData.pointerCount,
- mCurrentRawPointerData.pointerCount);
- } else {
- ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
- "hovering ids 0x%08x -> 0x%08x",
- mLastRawPointerData.pointerCount,
- mCurrentRawPointerData.pointerCount,
- mLastRawPointerData.touchingIdBits.value,
- mCurrentRawPointerData.touchingIdBits.value,
- mLastRawPointerData.hoveringIdBits.value,
- mCurrentRawPointerData.hoveringIdBits.value);
- }
+ ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
+ "hovering ids 0x%08x -> 0x%08x",
+ last->rawPointerData.pointerCount,
+ next->rawPointerData.pointerCount,
+ last->rawPointerData.touchingIdBits.value,
+ next->rawPointerData.touchingIdBits.value,
+ last->rawPointerData.hoveringIdBits.value,
+ next->rawPointerData.hoveringIdBits.value);
#endif
- // Reset state that we will compute below.
- mCurrentFingerIdBits.clear();
- mCurrentStylusIdBits.clear();
- mCurrentMouseIdBits.clear();
- mCurrentCookedPointerData.clear();
+ processRawTouches(false /*timeout*/);
+}
+void TouchInputMapper::processRawTouches(bool timeout) {
if (mDeviceMode == DEVICE_MODE_DISABLED) {
// Drop all input if the device is disabled.
- mCurrentRawPointerData.clear();
- mCurrentButtonState = 0;
+ mCurrentRawState.clear();
+ mRawStatesPending.clear();
+ return;
+ }
+
+ // Drain any pending touch states. The invariant here is that the mCurrentRawState is always
+ // valid and must go through the full cook and dispatch cycle. This ensures that anything
+ // touching the current state will only observe the events that have been dispatched to the
+ // rest of the pipeline.
+ const size_t N = mRawStatesPending.size();
+ size_t count;
+ for(count = 0; count < N; count++) {
+ const RawState& next = mRawStatesPending[count];
+
+ // A failure to assign the stylus id means that we're waiting on stylus data
+ // and so should defer the rest of the pipeline.
+ if (assignExternalStylusId(next, timeout)) {
+ break;
+ }
+
+ // All ready to go.
+ clearStylusDataPendingFlags();
+ mCurrentRawState.copyFrom(next);
+ if (mCurrentRawState.when < mLastRawState.when) {
+ mCurrentRawState.when = mLastRawState.when;
+ }
+ cookAndDispatch(mCurrentRawState.when);
+ }
+ if (count != 0) {
+ mRawStatesPending.removeItemsAt(0, count);
+ }
+
+ if (mExternalStylusDataPending) {
+ if (timeout) {
+ nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
+ clearStylusDataPendingFlags();
+ mCurrentRawState.copyFrom(mLastRawState);
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Timeout expired, synthesizing event with new stylus data");
+#endif
+ cookAndDispatch(when);
+ } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
+ mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+ }
+ }
+}
+
+void TouchInputMapper::cookAndDispatch(nsecs_t when) {
+ // Always start with a clean state.
+ mCurrentCookedState.clear();
+
+ // Apply stylus buttons to current raw state.
+ applyExternalStylusButtonState(when);
+
+ // Handle policy on initial down or hover events.
+ bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
+ && mCurrentRawState.rawPointerData.pointerCount != 0;
+
+ uint32_t policyFlags = 0;
+ bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
+ if (initialDown || buttonsPressed) {
+ // If this is a touch screen, hide the pointer on an initial down.
+ if (mDeviceMode == DEVICE_MODE_DIRECT) {
+ getContext()->fadePointer();
+ }
+
+ if (mParameters.wake) {
+ policyFlags |= POLICY_FLAG_WAKE;
+ }
+ }
+
+ // Consume raw off-screen touches before cooking pointer data.
+ // If touches are consumed, subsequent code will not receive any pointer data.
+ if (consumeRawTouches(when, policyFlags)) {
+ mCurrentRawState.rawPointerData.clear();
+ }
+
+ // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure
+ // with cooked pointer data that has the same ids and indices as the raw data.
+ // The following code can use either the raw or cooked data, as needed.
+ cookPointerData();
+
+ // Apply stylus pressure to current cooked state.
+ applyExternalStylusTouchState(when);
+
+ // Synthesize key down from raw buttons if needed.
+ synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
+ policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+
+ // Dispatch the touches either directly or by translation through a pointer on screen.
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
+ for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits);
+ !idBits.isEmpty(); ) {
+ uint32_t id = idBits.clearFirstMarkedBit();
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
+ if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
+ || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+ mCurrentCookedState.stylusIdBits.markBit(id);
+ } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
+ || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ mCurrentCookedState.fingerIdBits.markBit(id);
+ } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
+ mCurrentCookedState.mouseIdBits.markBit(id);
+ }
+ }
+ for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits);
+ !idBits.isEmpty(); ) {
+ uint32_t id = idBits.clearFirstMarkedBit();
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
+ if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
+ || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+ mCurrentCookedState.stylusIdBits.markBit(id);
+ }
+ }
+
+ // Stylus takes precedence over all tools, then mouse, then finger.
+ PointerUsage pointerUsage = mPointerUsage;
+ if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
+ mCurrentCookedState.mouseIdBits.clear();
+ mCurrentCookedState.fingerIdBits.clear();
+ pointerUsage = POINTER_USAGE_STYLUS;
+ } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
+ mCurrentCookedState.fingerIdBits.clear();
+ pointerUsage = POINTER_USAGE_MOUSE;
+ } else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
+ isPointerDown(mCurrentRawState.buttonState)) {
+ pointerUsage = POINTER_USAGE_GESTURES;
+ }
+
+ dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
- // Preprocess pointer data.
- if (!havePointerIds) {
- assignPointerIds();
+ if (mDeviceMode == DEVICE_MODE_DIRECT
+ && mConfig.showTouches && mPointerController != NULL) {
+ mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
+ mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+
+ mPointerController->setButtonState(mCurrentRawState.buttonState);
+ mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.touchingIdBits);
}
- // Handle policy on initial down or hover events.
- uint32_t policyFlags = 0;
- bool initialDown = mLastRawPointerData.pointerCount == 0
- && mCurrentRawPointerData.pointerCount != 0;
- bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
- if (initialDown || buttonsPressed) {
- // If this is a touch screen, hide the pointer on an initial down.
- if (mDeviceMode == DEVICE_MODE_DIRECT) {
- getContext()->fadePointer();
- }
-
- if (mParameters.wake) {
- policyFlags |= POLICY_FLAG_WAKE;
- }
- }
-
- // Synthesize key down from raw buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
- policyFlags, mLastButtonState, mCurrentButtonState);
-
- // Consume raw off-screen touches before cooking pointer data.
- // If touches are consumed, subsequent code will not receive any pointer data.
- if (consumeRawTouches(when, policyFlags)) {
- mCurrentRawPointerData.clear();
- }
-
- // Cook pointer data. This call populates the mCurrentCookedPointerData structure
- // with cooked pointer data that has the same ids and indices as the raw data.
- // The following code can use either the raw or cooked data, as needed.
- cookPointerData();
-
- // Dispatch the touches either directly or by translation through a pointer on screen.
- if (mDeviceMode == DEVICE_MODE_POINTER) {
- for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
- uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
- if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
- || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
- mCurrentStylusIdBits.markBit(id);
- } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
- || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
- mCurrentFingerIdBits.markBit(id);
- } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
- mCurrentMouseIdBits.markBit(id);
- }
- }
- for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
- uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
- if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
- || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
- mCurrentStylusIdBits.markBit(id);
- }
- }
-
- // Stylus takes precedence over all tools, then mouse, then finger.
- PointerUsage pointerUsage = mPointerUsage;
- if (!mCurrentStylusIdBits.isEmpty()) {
- mCurrentMouseIdBits.clear();
- mCurrentFingerIdBits.clear();
- pointerUsage = POINTER_USAGE_STYLUS;
- } else if (!mCurrentMouseIdBits.isEmpty()) {
- mCurrentFingerIdBits.clear();
- pointerUsage = POINTER_USAGE_MOUSE;
- } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
- pointerUsage = POINTER_USAGE_GESTURES;
- }
-
- dispatchPointerUsage(when, policyFlags, pointerUsage);
- } else {
- if (mDeviceMode == DEVICE_MODE_DIRECT
- && mConfig.showTouches && mPointerController != NULL) {
- mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
- mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-
- mPointerController->setButtonState(mCurrentButtonState);
- mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mCurrentCookedPointerData.touchingIdBits);
- }
-
+ if (!mCurrentMotionAborted) {
+ dispatchButtonRelease(when, policyFlags);
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
+ dispatchButtonPress(when, policyFlags);
}
- // Synthesize key up from raw buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
- policyFlags, mLastButtonState, mCurrentButtonState);
+ if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
+ mCurrentMotionAborted = false;
+ }
}
- // Copy current touch to last touch in preparation for the next cycle.
- mLastRawPointerData.copyFrom(mCurrentRawPointerData);
- mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
- mLastButtonState = mCurrentButtonState;
- mLastFingerIdBits = mCurrentFingerIdBits;
- mLastStylusIdBits = mCurrentStylusIdBits;
- mLastMouseIdBits = mCurrentMouseIdBits;
+ // Synthesize key up from raw buttons if needed.
+ synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
+ policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
// Clear some transient state.
- mCurrentRawVScroll = 0;
- mCurrentRawHScroll = 0;
+ mCurrentRawState.rawVScroll = 0;
+ mCurrentRawState.rawHScroll = 0;
+
+ // Copy current touch to last touch in preparation for the next cycle.
+ mLastRawState.copyFrom(mCurrentRawState);
+ mLastCookedState.copyFrom(mCurrentCookedState);
+}
+
+void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
+ if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
+ mCurrentRawState.buttonState |= mExternalStylusState.buttons;
+ }
+}
+
+void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) {
+ CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData;
+ const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData;
+
+ if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) {
+ float pressure = mExternalStylusState.pressure;
+ if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) {
+ const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId);
+ pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
+ }
+ PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
+
+ PointerProperties& properties =
+ currentPointerData.editPointerPropertiesWithId(mExternalStylusId);
+ if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ properties.toolType = mExternalStylusState.toolType;
+ }
+ }
+}
+
+bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
+ if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) {
+ return false;
+ }
+
+ const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
+ && state.rawPointerData.pointerCount != 0;
+ if (initialDown) {
+ if (mExternalStylusState.pressure != 0.0f) {
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Have both stylus and touch data, beginning fusion");
+#endif
+ mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit();
+ } else if (timeout) {
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Timeout expired, assuming touch is not a stylus.");
+#endif
+ resetExternalStylus();
+ } else {
+ if (mExternalStylusFusionTimeout == LLONG_MAX) {
+ mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
+ }
+#if DEBUG_STYLUS_FUSION
+ ALOGD("No stylus data but stylus is connected, requesting timeout "
+ "(%" PRId64 "ms)", mExternalStylusFusionTimeout);
+#endif
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+ return true;
+ }
+ }
+
+ // Check if the stylus pointer has gone up.
+ if (mExternalStylusId != -1 &&
+ !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) {
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Stylus pointer is going up");
+#endif
+ mExternalStylusId = -1;
+ }
+
+ return false;
}
void TouchInputMapper::timeoutExpired(nsecs_t when) {
@@ -3889,13 +4189,30 @@
if (mPointerUsage == POINTER_USAGE_GESTURES) {
dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
}
+ } else if (mDeviceMode == DEVICE_MODE_DIRECT) {
+ if (mExternalStylusFusionTimeout < when) {
+ processRawTouches(true /*timeout*/);
+ } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+ }
+ }
+}
+
+void TouchInputMapper::updateExternalStylusState(const StylusState& state) {
+ mExternalStylusState.copyFrom(state);
+ if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
+ // We're either in the middle of a fused stream of data or we're waiting on data before
+ // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
+ // data.
+ mExternalStylusDataPending = true;
+ processRawTouches(false /*timeout*/);
}
}
bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
// Check for release of a virtual key.
if (mCurrentVirtualKey.down) {
- if (mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+ if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
// Pointer went up while virtual key was down.
mCurrentVirtualKey.down = false;
if (!mCurrentVirtualKey.ignored) {
@@ -3910,9 +4227,10 @@
return true;
}
- if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
- uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+ if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
+ uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
// Pointer is still within the space of the virtual key.
@@ -3937,15 +4255,15 @@
}
}
- if (mLastRawPointerData.touchingIdBits.isEmpty()
- && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+ if (mLastRawState.rawPointerData.touchingIdBits.isEmpty()
+ && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
// Pointer just went down. Check for virtual key press or off-screen touches.
- uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+ uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+ const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
if (!isPointInsideSurface(pointer.x, pointer.y)) {
// If exactly one pointer went down, check for virtual key hit.
// Otherwise we will drop the entire stroke.
- if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
+ if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
if (virtualKey) {
mCurrentVirtualKey.down = true;
@@ -3985,7 +4303,8 @@
// area and accidentally triggers a virtual key. This often happens when virtual keys
// are layed out below the screen near to where the on screen keyboard's space bar
// is displayed.
- if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+ if (mConfig.virtualKeyQuietTime > 0 &&
+ !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
}
return false;
@@ -4004,22 +4323,38 @@
getListener()->notifyKey(&args);
}
+void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
+ BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
+ if (!currentIdBits.isEmpty()) {
+ int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t buttonState = mCurrentCookedState.buttonState;
+ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ currentIdBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mCurrentMotionAborted = true;
+ }
+}
+
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
- BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
- BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
+ BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
+ BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
int32_t metaState = getContext()->getGlobalMetaState();
- int32_t buttonState = mCurrentButtonState;
+ int32_t buttonState = mCurrentCookedState.buttonState;
if (currentIdBits == lastIdBits) {
if (!currentIdBits.isEmpty()) {
// No pointer id changes so this is a move event.
// The listener takes care of batching moves so we don't have to deal with that here.
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
currentIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
@@ -4034,14 +4369,14 @@
// Update last coordinates of pointers that have moved so that we observe the new
// pointer positions at the same time as other pointers that have just gone up.
bool moveNeeded = updateMovedPointers(
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mLastCookedPointerData.pointerProperties,
- mLastCookedPointerData.pointerCoords,
- mLastCookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
moveIdBits);
- if (buttonState != mLastButtonState) {
+ if (buttonState != mLastCookedState.buttonState) {
moveNeeded = true;
}
@@ -4050,27 +4385,25 @@
uint32_t upId = upIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
- mLastCookedPointerData.pointerProperties,
- mLastCookedPointerData.pointerCoords,
- mLastCookedPointerData.idToIndex,
- dispatchedIdBits, upId,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
dispatchedIdBits.clearBit(upId);
}
// Dispatch move events if any of the remaining pointers moved from their old locations.
// Although applications receive new locations as part of individual pointer up
// events, they do not generally handle them except when presented in a move event.
- if (moveNeeded) {
+ if (moveNeeded && !moveIdBits.isEmpty()) {
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- dispatchedIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
// Dispatch pointer down events using the new pointer locations.
@@ -4084,69 +4417,119 @@
}
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- dispatchedIdBits, downId,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
}
void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) {
if (mSentHoverEnter &&
- (mCurrentCookedPointerData.hoveringIdBits.isEmpty()
- || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) {
+ (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()
+ || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
int32_t metaState = getContext()->getGlobalMetaState();
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
- mLastCookedPointerData.pointerProperties,
- mLastCookedPointerData.pointerCoords,
- mLastCookedPointerData.idToIndex,
- mLastCookedPointerData.hoveringIdBits, -1,
+ AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
+ mLastCookedState.cookedPointerData.hoveringIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
mSentHoverEnter = false;
}
}
void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) {
- if (mCurrentCookedPointerData.touchingIdBits.isEmpty()
- && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) {
+ if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty()
+ && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
if (!mSentHoverEnter) {
- dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mCurrentCookedPointerData.hoveringIdBits, -1,
+ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER,
+ 0, 0, metaState, mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
mSentHoverEnter = true;
}
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mCurrentCookedPointerData.hoveringIdBits, -1,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
-void TouchInputMapper::cookPointerData() {
- uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
+void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) {
+ BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState);
+ const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData);
+ const int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t buttonState = mLastCookedState.buttonState;
+ while (!releasedButtons.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit());
+ buttonState &= ~actionButton;
+ dispatchMotion(when, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton,
+ 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ }
+}
- mCurrentCookedPointerData.clear();
- mCurrentCookedPointerData.pointerCount = currentPointerCount;
- mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits;
- mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits;
+void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) {
+ BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState);
+ const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData);
+ const int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t buttonState = mLastCookedState.buttonState;
+ while (!pressedButtons.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
+ buttonState |= actionButton;
+ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
+ 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ }
+}
+
+const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) {
+ if (!cookedPointerData.touchingIdBits.isEmpty()) {
+ return cookedPointerData.touchingIdBits;
+ }
+ return cookedPointerData.hoveringIdBits;
+}
+
+void TouchInputMapper::cookPointerData() {
+ uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
+
+ mCurrentCookedState.cookedPointerData.clear();
+ mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
+ mCurrentCookedState.cookedPointerData.hoveringIdBits =
+ mCurrentRawState.rawPointerData.hoveringIdBits;
+ mCurrentCookedState.cookedPointerData.touchingIdBits =
+ mCurrentRawState.rawPointerData.touchingIdBits;
+
+ if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
+ mCurrentCookedState.buttonState = 0;
+ } else {
+ mCurrentCookedState.buttonState = mCurrentRawState.buttonState;
+ }
// Walk through the the active pointers and map device coordinates onto
// surface coordinates and adjust for display orientation.
for (uint32_t i = 0; i < currentPointerCount; i++) {
- const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i];
+ const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
// Size
float touchMajor, touchMinor, toolMajor, toolMinor, size;
@@ -4185,7 +4568,8 @@
}
if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
- uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count();
+ uint32_t touchingCount =
+ mCurrentRawState.rawPointerData.touchingIdBits.count();
if (touchingCount > 1) {
touchMajor /= touchingCount;
touchMinor /= touchingCount;
@@ -4315,7 +4699,7 @@
bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
orientation -= M_PI_2;
- if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {
+ if (orientation < mOrientedRanges.orientation.min) {
orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
}
break;
@@ -4327,7 +4711,7 @@
bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
orientation -= M_PI;
- if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {
+ if (orientation < mOrientedRanges.orientation.min) {
orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
}
break;
@@ -4339,7 +4723,7 @@
bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
orientation += M_PI_2;
- if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) {
+ if (orientation > mOrientedRanges.orientation.max) {
orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
}
break;
@@ -4354,7 +4738,7 @@
}
// Write output coords.
- PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i];
+ PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
out.clear();
out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
@@ -4376,14 +4760,15 @@
}
// Write output properties.
- PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i];
+ PointerProperties& properties =
+ mCurrentCookedState.cookedPointerData.pointerProperties[i];
uint32_t id = in.id;
properties.clear();
properties.id = id;
properties.toolType = in.toolType;
// Write id index.
- mCurrentCookedPointerData.idToIndex[id] = i;
+ mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
}
}
@@ -4487,7 +4872,7 @@
// Send events!
int32_t metaState = getContext()->getGlobalMetaState();
- int32_t buttonState = mCurrentButtonState;
+ int32_t buttonState = mCurrentCookedState.buttonState;
// Update last coordinates of pointers that have moved so that we observe the new
// pointer positions at the same time as other pointers that have just gone up.
@@ -4508,7 +4893,7 @@
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
movedGestureIdBits);
- if (buttonState != mLastButtonState) {
+ if (buttonState != mLastCookedState.buttonState) {
moveNeeded = true;
}
}
@@ -4518,12 +4903,12 @@
if (!dispatchedGestureIdBits.isEmpty()) {
if (cancelPreviousGesture) {
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
+ AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
- dispatchedGestureIdBits, -1,
- 0, 0, mPointerGesture.downTime);
+ dispatchedGestureIdBits, -1, 0,
+ 0, mPointerGesture.downTime);
dispatchedGestureIdBits.clear();
} else {
@@ -4538,7 +4923,7 @@
uint32_t id = upGestureIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_UP, 0,
+ AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
@@ -4553,7 +4938,8 @@
// Send motion events for all pointers that moved.
if (moveNeeded) {
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
+ AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
dispatchedGestureIdBits, -1,
@@ -4573,7 +4959,7 @@
}
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
dispatchedGestureIdBits, id,
@@ -4584,7 +4970,7 @@
// Send motion events for hover.
if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
@@ -4610,7 +4996,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mViewport.displayId, 1, &pointerProperties, &pointerCoords,
0, 0, mPointerGesture.downTime);
@@ -4639,9 +5025,9 @@
// Cancel previously dispatches pointers.
if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
- int32_t buttonState = mCurrentButtonState;
+ int32_t buttonState = mCurrentRawState.buttonState;
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
+ AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
@@ -4696,21 +5082,22 @@
return false;
}
- const uint32_t currentFingerCount = mCurrentFingerIdBits.count();
- const uint32_t lastFingerCount = mLastFingerIdBits.count();
+ const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
+ const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count();
// Update the velocity tracker.
{
VelocityTracker::Position positions[MAX_POINTERS];
uint32_t count = 0;
- for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) {
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) {
uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
positions[count].x = pointer.x * mPointerXMovementScale;
positions[count].y = pointer.y * mPointerYMovementScale;
}
mPointerGesture.velocityTracker.addMovement(when,
- mCurrentFingerIdBits, positions);
+ mCurrentCookedState.fingerIdBits, positions);
}
// If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
@@ -4730,17 +5117,17 @@
int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
int32_t activeTouchId = lastActiveTouchId;
if (activeTouchId < 0) {
- if (!mCurrentFingerIdBits.isEmpty()) {
+ if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
activeTouchChanged = true;
activeTouchId = mPointerGesture.activeTouchId =
- mCurrentFingerIdBits.firstMarkedBit();
+ mCurrentCookedState.fingerIdBits.firstMarkedBit();
mPointerGesture.firstTouchTime = when;
}
- } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) {
+ } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) {
activeTouchChanged = true;
- if (!mCurrentFingerIdBits.isEmpty()) {
+ if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
activeTouchId = mPointerGesture.activeTouchId =
- mCurrentFingerIdBits.firstMarkedBit();
+ mCurrentCookedState.fingerIdBits.firstMarkedBit();
} else {
activeTouchId = mPointerGesture.activeTouchId = -1;
}
@@ -4763,7 +5150,7 @@
isQuietTime = true;
} else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
&& currentFingerCount >= 2
- && !isPointerDown(mCurrentButtonState)) {
+ && !isPointerDown(mCurrentRawState.buttonState)) {
// Enter quiet time when releasing the button and there are still two or more
// fingers down. This may indicate that one finger was used to press the button
// but it has not gone up yet.
@@ -4791,7 +5178,7 @@
mPointerGesture.currentGestureIdBits.clear();
mPointerVelocityControl.reset();
- } else if (isPointerDown(mCurrentButtonState)) {
+ } else if (isPointerDown(mCurrentRawState.buttonState)) {
// Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
// The pointer follows the active touch point.
// Emit DOWN, MOVE, UP events at the pointer location.
@@ -4820,7 +5207,7 @@
if (activeTouchId >= 0 && currentFingerCount > 1) {
int32_t bestId = -1;
float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
- for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) {
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
float vx, vy;
if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
@@ -4841,11 +5228,11 @@
}
}
- if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) {
+ if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
const RawPointerData::Pointer& currentPointer =
- mCurrentRawPointerData.pointerForId(activeTouchId);
+ mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
const RawPointerData::Pointer& lastPointer =
- mLastRawPointerData.pointerForId(activeTouchId);
+ mLastRawState.rawPointerData.pointerForId(activeTouchId);
float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
@@ -4981,11 +5368,11 @@
mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
}
- if (mLastFingerIdBits.hasBit(activeTouchId)) {
+ if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
const RawPointerData::Pointer& currentPointer =
- mCurrentRawPointerData.pointerForId(activeTouchId);
+ mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
const RawPointerData::Pointer& lastPointer =
- mLastRawPointerData.pointerForId(activeTouchId);
+ mLastRawState.rawPointerData.pointerForId(activeTouchId);
float deltaX = (currentPointer.x - lastPointer.x)
* mPointerXMovementScale;
float deltaY = (currentPointer.y - lastPointer.y)
@@ -5090,7 +5477,7 @@
+ mConfig.pointerGestureMultitouchSettleInterval - when)
* 0.000001f);
#endif
- mCurrentRawPointerData.getCentroidOfTouchingPointers(
+ mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers(
&mPointerGesture.referenceTouchX,
&mPointerGesture.referenceTouchY);
mPointerController->getPosition(&mPointerGesture.referenceGestureX,
@@ -5098,23 +5485,23 @@
}
// Clear the reference deltas for fingers not yet included in the reference calculation.
- for (BitSet32 idBits(mCurrentFingerIdBits.value
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value
& ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
mPointerGesture.referenceDeltas[id].dx = 0;
mPointerGesture.referenceDeltas[id].dy = 0;
}
- mPointerGesture.referenceIdBits = mCurrentFingerIdBits;
+ mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits;
// Add delta for all fingers and calculate a common movement delta.
float commonDeltaX = 0, commonDeltaY = 0;
- BitSet32 commonIdBits(mLastFingerIdBits.value
- & mCurrentFingerIdBits.value);
+ BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value
+ & mCurrentCookedState.fingerIdBits.value);
for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
bool first = (idBits == commonIdBits);
uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id);
- const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id);
+ const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id);
+ const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id);
PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
delta.dx += cpd.x - lpd.x;
delta.dy += cpd.y - lpd.y;
@@ -5155,11 +5542,13 @@
mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
} else {
// There are exactly two pointers.
- BitSet32 idBits(mCurrentFingerIdBits);
+ BitSet32 idBits(mCurrentCookedState.fingerIdBits);
uint32_t id1 = idBits.clearFirstMarkedBit();
uint32_t id2 = idBits.firstMarkedBit();
- const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1);
- const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2);
+ const RawPointerData::Pointer& p1 =
+ mCurrentRawState.rawPointerData.pointerForId(id1);
+ const RawPointerData::Pointer& p2 =
+ mCurrentRawState.rawPointerData.pointerForId(id2);
float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
if (mutualDistance > mPointerGestureMaxSwipeWidth) {
// There are two pointers but they are too far apart for a SWIPE,
@@ -5305,14 +5694,14 @@
} else {
// Otherwise, assume we mapped all touches from the previous frame.
// Reuse all mappings that are still applicable.
- mappedTouchIdBits.value = mLastFingerIdBits.value
- & mCurrentFingerIdBits.value;
+ mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value
+ & mCurrentCookedState.fingerIdBits.value;
usedGestureIdBits = mPointerGesture.lastGestureIdBits;
// Check whether we need to choose a new active gesture id because the
// current went went up.
- for (BitSet32 upTouchIdBits(mLastFingerIdBits.value
- & ~mCurrentFingerIdBits.value);
+ for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value
+ & ~mCurrentCookedState.fingerIdBits.value);
!upTouchIdBits.isEmpty(); ) {
uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
@@ -5331,7 +5720,7 @@
mPointerGesture.activeGestureId);
#endif
- BitSet32 idBits(mCurrentFingerIdBits);
+ BitSet32 idBits(mCurrentCookedState.fingerIdBits);
for (uint32_t i = 0; i < currentFingerCount; i++) {
uint32_t touchId = idBits.clearFirstMarkedBit();
uint32_t gestureId;
@@ -5355,7 +5744,7 @@
mPointerGesture.currentGestureIdToIndex[gestureId] = i;
const RawPointerData::Pointer& pointer =
- mCurrentRawPointerData.pointerForId(touchId);
+ mCurrentRawState.rawPointerData.pointerForId(touchId);
float deltaX = (pointer.x - mPointerGesture.referenceTouchX)
* mPointerXZoomScale;
float deltaY = (pointer.y - mPointerGesture.referenceTouchY)
@@ -5386,7 +5775,7 @@
}
}
- mPointerController->setButtonState(mCurrentButtonState);
+ mPointerController->setButtonState(mCurrentRawState.buttonState);
#if DEBUG_GESTURES
ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
@@ -5428,23 +5817,24 @@
mPointerSimple.currentProperties.clear();
bool down, hovering;
- if (!mCurrentStylusIdBits.isEmpty()) {
- uint32_t id = mCurrentStylusIdBits.firstMarkedBit();
- uint32_t index = mCurrentCookedPointerData.idToIndex[id];
- float x = mCurrentCookedPointerData.pointerCoords[index].getX();
- float y = mCurrentCookedPointerData.pointerCoords[index].getY();
+ if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
+ uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit();
+ uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id];
+ float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX();
+ float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY();
mPointerController->setPosition(x, y);
- hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id);
+ hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id);
down = !hovering;
mPointerController->getPosition(&x, &y);
- mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]);
+ mPointerSimple.currentCoords.copyFrom(
+ mCurrentCookedState.cookedPointerData.pointerCoords[index]);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerSimple.currentProperties.id = 0;
mPointerSimple.currentProperties.toolType =
- mCurrentCookedPointerData.pointerProperties[index].toolType;
+ mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType;
} else {
down = false;
hovering = false;
@@ -5462,16 +5852,16 @@
mPointerSimple.currentProperties.clear();
bool down, hovering;
- if (!mCurrentMouseIdBits.isEmpty()) {
- uint32_t id = mCurrentMouseIdBits.firstMarkedBit();
- uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id];
- if (mLastMouseIdBits.hasBit(id)) {
- uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id];
- float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x
- - mLastRawPointerData.pointers[lastIndex].x)
+ if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
+ uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit();
+ uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
+ if (mLastCookedState.mouseIdBits.hasBit(id)) {
+ uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id];
+ float deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x
+ - mLastRawState.rawPointerData.pointers[lastIndex].x)
* mPointerXMovementScale;
- float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y
- - mLastRawPointerData.pointers[lastIndex].y)
+ float deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y
+ - mLastRawState.rawPointerData.pointers[lastIndex].y)
* mPointerYMovementScale;
rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
@@ -5482,20 +5872,20 @@
mPointerVelocityControl.reset();
}
- down = isPointerDown(mCurrentButtonState);
+ down = isPointerDown(mCurrentRawState.buttonState);
hovering = !down;
float x, y;
mPointerController->getPosition(&x, &y);
mPointerSimple.currentCoords.copyFrom(
- mCurrentCookedPointerData.pointerCoords[currentIndex]);
+ mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
hovering ? 0.0f : 1.0f);
mPointerSimple.currentProperties.id = 0;
mPointerSimple.currentProperties.toolType =
- mCurrentCookedPointerData.pointerProperties[currentIndex].toolType;
+ mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType;
} else {
mPointerVelocityControl.reset();
@@ -5520,7 +5910,7 @@
if (down || hovering) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
mPointerController->clearSpots();
- mPointerController->setButtonState(mCurrentButtonState);
+ mPointerController->setButtonState(mCurrentRawState.buttonState);
mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
} else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -5532,7 +5922,7 @@
// Send up.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0,
+ AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5545,7 +5935,7 @@
// Send hover exit.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
+ AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5560,7 +5950,7 @@
// Send down.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5570,7 +5960,7 @@
// Send move.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5584,7 +5974,8 @@
// Send hover enter.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5594,7 +5985,8 @@
// Send hover move.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5602,9 +5994,9 @@
getListener()->notifyMotion(&args);
}
- if (mCurrentRawVScroll || mCurrentRawHScroll) {
- float vscroll = mCurrentRawVScroll;
- float hscroll = mCurrentRawHScroll;
+ if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
+ float vscroll = mCurrentRawState.rawVScroll;
+ float hscroll = mCurrentRawState.rawHScroll;
mWheelYVelocityControl.move(when, NULL, &vscroll);
mWheelXVelocityControl.move(when, &hscroll, NULL);
@@ -5615,7 +6007,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &pointerCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5640,10 +6032,11 @@
}
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+ int32_t action, int32_t actionButton, int32_t flags,
+ int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
- const uint32_t* idToIndex, BitSet32 idBits,
- int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
+ const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
+ float xPrecision, float yPrecision, nsecs_t downTime) {
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
@@ -5677,7 +6070,7 @@
}
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
- action, flags, metaState, buttonState, edgeFlags,
+ action, actionButton, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
@@ -5717,6 +6110,11 @@
}
}
+void TouchInputMapper::cancelTouch(nsecs_t when) {
+ abortPointerUsage(when, 0 /*policyFlags*/);
+ abortTouches(when, 0 /* policyFlags*/);
+}
+
bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue
&& y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue;
@@ -5745,11 +6143,11 @@
return NULL;
}
-void TouchInputMapper::assignPointerIds() {
- uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
- uint32_t lastPointerCount = mLastRawPointerData.pointerCount;
+void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) {
+ uint32_t currentPointerCount = current->rawPointerData.pointerCount;
+ uint32_t lastPointerCount = last->rawPointerData.pointerCount;
- mCurrentRawPointerData.clearIdBits();
+ current->rawPointerData.clearIdBits();
if (currentPointerCount == 0) {
// No pointers to assign.
@@ -5760,21 +6158,21 @@
// All pointers are new.
for (uint32_t i = 0; i < currentPointerCount; i++) {
uint32_t id = i;
- mCurrentRawPointerData.pointers[i].id = id;
- mCurrentRawPointerData.idToIndex[id] = i;
- mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i));
+ current->rawPointerData.pointers[i].id = id;
+ current->rawPointerData.idToIndex[id] = i;
+ current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i));
}
return;
}
if (currentPointerCount == 1 && lastPointerCount == 1
- && mCurrentRawPointerData.pointers[0].toolType
- == mLastRawPointerData.pointers[0].toolType) {
+ && current->rawPointerData.pointers[0].toolType
+ == last->rawPointerData.pointers[0].toolType) {
// Only one pointer and no change in count so it must have the same id as before.
- uint32_t id = mLastRawPointerData.pointers[0].id;
- mCurrentRawPointerData.pointers[0].id = id;
- mCurrentRawPointerData.idToIndex[id] = 0;
- mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0));
+ uint32_t id = last->rawPointerData.pointers[0].id;
+ current->rawPointerData.pointers[0].id = id;
+ current->rawPointerData.idToIndex[id] = 0;
+ current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0));
return;
}
@@ -5792,9 +6190,9 @@
for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
lastPointerIndex++) {
const RawPointerData::Pointer& currentPointer =
- mCurrentRawPointerData.pointers[currentPointerIndex];
+ current->rawPointerData.pointers[currentPointerIndex];
const RawPointerData::Pointer& lastPointer =
- mLastRawPointerData.pointers[lastPointerIndex];
+ last->rawPointerData.pointers[lastPointerIndex];
if (currentPointer.toolType == lastPointer.toolType) {
int64_t deltaX = currentPointer.x - lastPointer.x;
int64_t deltaY = currentPointer.y - lastPointer.y;
@@ -5900,11 +6298,11 @@
matchedCurrentBits.markBit(currentPointerIndex);
matchedLastBits.markBit(lastPointerIndex);
- uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id;
- mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
- mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
- mCurrentRawPointerData.markIdBit(id,
- mCurrentRawPointerData.isHovering(currentPointerIndex));
+ uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id;
+ current->rawPointerData.pointers[currentPointerIndex].id = id;
+ current->rawPointerData.idToIndex[id] = currentPointerIndex;
+ current->rawPointerData.markIdBit(id,
+ current->rawPointerData.isHovering(currentPointerIndex));
usedIdBits.markBit(id);
#if DEBUG_POINTER_ASSIGNMENT
@@ -5920,10 +6318,10 @@
uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
uint32_t id = usedIdBits.markFirstUnmarkedBit();
- mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
- mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
- mCurrentRawPointerData.markIdBit(id,
- mCurrentRawPointerData.isHovering(currentPointerIndex));
+ current->rawPointerData.pointers[currentPointerIndex].id = id;
+ current->rawPointerData.idToIndex[id] = currentPointerIndex;
+ current->rawPointerData.markIdBit(id,
+ current->rawPointerData.isHovering(currentPointerIndex));
#if DEBUG_POINTER_ASSIGNMENT
ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
@@ -6002,18 +6400,18 @@
mSingleTouchMotionAccumulator.process(rawEvent);
}
-void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
+void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
if (mTouchButtonAccumulator.isToolActive()) {
- mCurrentRawPointerData.pointerCount = 1;
- mCurrentRawPointerData.idToIndex[0] = 0;
+ outState->rawPointerData.pointerCount = 1;
+ outState->rawPointerData.idToIndex[0] = 0;
bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
&& (mTouchButtonAccumulator.isHovering()
|| (mRawPointerAxes.pressure.valid
&& mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
- mCurrentRawPointerData.markIdBit(0, isHovering);
+ outState->rawPointerData.markIdBit(0, isHovering);
- RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0];
+ RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0];
outPointer.id = 0;
outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
@@ -6074,7 +6472,7 @@
mMultiTouchMotionAccumulator.process(rawEvent);
}
-void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
+void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
BitSet32 newPointerIdBits;
@@ -6095,7 +6493,7 @@
break; // too many fingers!
}
- RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount];
+ RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
outPointer.x = inSlot->getX();
outPointer.y = inSlot->getY();
outPointer.pressure = inSlot->getPressure();
@@ -6122,38 +6520,37 @@
outPointer.isHovering = isHovering;
// Assign pointer id using tracking id if available.
- if (*outHavePointerIds) {
- int32_t trackingId = inSlot->getTrackingId();
- int32_t id = -1;
- if (trackingId >= 0) {
- for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
- uint32_t n = idBits.clearFirstMarkedBit();
- if (mPointerTrackingIdMap[n] == trackingId) {
- id = n;
- }
+ mHavePointerIds = true;
+ int32_t trackingId = inSlot->getTrackingId();
+ int32_t id = -1;
+ if (trackingId >= 0) {
+ for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
+ uint32_t n = idBits.clearFirstMarkedBit();
+ if (mPointerTrackingIdMap[n] == trackingId) {
+ id = n;
}
+ }
- if (id < 0 && !mPointerIdBits.isFull()) {
- id = mPointerIdBits.markFirstUnmarkedBit();
- mPointerTrackingIdMap[id] = trackingId;
- }
+ if (id < 0 && !mPointerIdBits.isFull()) {
+ id = mPointerIdBits.markFirstUnmarkedBit();
+ mPointerTrackingIdMap[id] = trackingId;
}
- if (id < 0) {
- *outHavePointerIds = false;
- mCurrentRawPointerData.clearIdBits();
- newPointerIdBits.clear();
- } else {
- outPointer.id = id;
- mCurrentRawPointerData.idToIndex[id] = outCount;
- mCurrentRawPointerData.markIdBit(id, isHovering);
- newPointerIdBits.markBit(id);
- }
+ }
+ if (id < 0) {
+ mHavePointerIds = false;
+ outState->rawPointerData.clearIdBits();
+ newPointerIdBits.clear();
+ } else {
+ outPointer.id = id;
+ outState->rawPointerData.idToIndex[id] = outCount;
+ outState->rawPointerData.markIdBit(id, isHovering);
+ newPointerIdBits.markBit(id);
}
outCount += 1;
}
- mCurrentRawPointerData.pointerCount = outCount;
+ outState->rawPointerData.pointerCount = outCount;
mPointerIdBits = newPointerIdBits;
mMultiTouchMotionAccumulator.finishSync();
@@ -6197,6 +6594,77 @@
|| mTouchButtonAccumulator.hasStylus();
}
+// --- ExternalStylusInputMapper
+
+ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) :
+ InputMapper(device) {
+
+}
+
+uint32_t ExternalStylusInputMapper::getSources() {
+ return AINPUT_SOURCE_STYLUS;
+}
+
+void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+ info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+}
+
+void ExternalStylusInputMapper::dump(String8& dump) {
+ dump.append(INDENT2 "External Stylus Input Mapper:\n");
+ dump.append(INDENT3 "Raw Stylus Axes:\n");
+ dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure");
+ dump.append(INDENT3 "Stylus State:\n");
+ dumpStylusState(dump, mStylusState);
+}
+
+void ExternalStylusInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config, uint32_t changes) {
+ getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis);
+ mTouchButtonAccumulator.configure(getDevice());
+}
+
+void ExternalStylusInputMapper::reset(nsecs_t when) {
+ InputDevice* device = getDevice();
+ mSingleTouchMotionAccumulator.reset(device);
+ mTouchButtonAccumulator.reset(device);
+ InputMapper::reset(when);
+}
+
+void ExternalStylusInputMapper::process(const RawEvent* rawEvent) {
+ mSingleTouchMotionAccumulator.process(rawEvent);
+ mTouchButtonAccumulator.process(rawEvent);
+
+ if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+ sync(rawEvent->when);
+ }
+}
+
+void ExternalStylusInputMapper::sync(nsecs_t when) {
+ mStylusState.clear();
+
+ mStylusState.when = when;
+
+ mStylusState.toolType = mTouchButtonAccumulator.getToolType();
+ if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ }
+
+ int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
+ if (mRawPressureAxis.valid) {
+ mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue;
+ } else if (mTouchButtonAccumulator.isToolActive()) {
+ mStylusState.pressure = 1.0f;
+ } else {
+ mStylusState.pressure = 0.0f;
+ }
+
+ mStylusState.buttons = mTouchButtonAccumulator.getButtonState();
+
+ mContext->dispatchExternalStylusState(mStylusState);
+}
+
// --- JoystickInputMapper ---
@@ -6520,7 +6988,7 @@
uint32_t policyFlags = 0;
NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
getListener()->notifyMotion(&args);
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index c5896d4..7cb4680 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -139,7 +139,10 @@
CHANGE_DEVICE_ALIAS = 1 << 5,
// The location calibration matrix changed.
- TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+ CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+
+ // The presence of an external stylus has changed.
+ CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,
// All devices must be reopened.
CHANGE_MUST_REOPEN = 1 << 31,
@@ -371,6 +374,31 @@
virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
};
+struct StylusState {
+ /* Time the stylus event was received. */
+ nsecs_t when;
+ /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */
+ float pressure;
+ /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */
+ uint32_t buttons;
+ /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */
+ int32_t toolType;
+
+ void copyFrom(const StylusState& other) {
+ when = other.when;
+ pressure = other.pressure;
+ buttons = other.buttons;
+ toolType = other.toolType;
+ }
+
+ void clear() {
+ when = LLONG_MAX;
+ pressure = 0.f;
+ buttons = 0;
+ toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
+ }
+};
+
/* Internal interface used by individual input devices to access global input device state
* and parameters maintained by the input reader.
@@ -392,6 +420,9 @@
virtual void requestTimeoutAtTime(nsecs_t when) = 0;
virtual int32_t bumpGeneration() = 0;
+ virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0;
+ virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
+
virtual InputReaderPolicyInterface* getPolicy() = 0;
virtual InputListenerInterface* getListener() = 0;
virtual EventHubInterface* getEventHub() = 0;
@@ -458,6 +489,8 @@
virtual void fadePointer();
virtual void requestTimeoutAtTime(nsecs_t when);
virtual int32_t bumpGeneration();
+ virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices);
+ virtual void dispatchExternalStylusState(const StylusState& outState);
virtual InputReaderPolicyInterface* getPolicy();
virtual InputListenerInterface* getListener();
virtual EventHubInterface* getEventHub();
@@ -496,6 +529,10 @@
void updateGlobalMetaStateLocked();
int32_t getGlobalMetaStateLocked();
+ void notifyExternalStylusPresenceChanged();
+ void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices);
+ void dispatchExternalStylusState(const StylusState& state);
+
void fadePointerLocked();
int32_t mGeneration;
@@ -555,6 +592,9 @@
inline bool isExternal() { return mIsExternal; }
inline void setExternal(bool external) { mIsExternal = external; }
+ inline void setMic(bool hasMic) { mHasMic = hasMic; }
+ inline bool hasMic() const { return mHasMic; }
+
inline bool isIgnored() { return mMappers.isEmpty(); }
void dump(String8& dump);
@@ -563,6 +603,7 @@
void reset(nsecs_t when);
void process(const RawEvent* rawEvents, size_t count);
void timeoutExpired(nsecs_t when);
+ void updateExternalStylusState(const StylusState& state);
void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
@@ -572,6 +613,7 @@
const int32_t* keyCodes, uint8_t* outFlags);
void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
void cancelVibrate(int32_t token);
+ void cancelTouch(nsecs_t when);
int32_t getMetaState();
@@ -617,6 +659,7 @@
uint32_t mSources;
bool mIsExternal;
+ bool mHasMic;
bool mDropUntilNextSync;
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
@@ -830,9 +873,21 @@
return pointerCoords[idToIndex[id]];
}
- inline bool isHovering(uint32_t pointerIndex) {
+ inline PointerCoords& editPointerCoordsWithId(uint32_t id) {
+ return pointerCoords[idToIndex[id]];
+ }
+
+ inline PointerProperties& editPointerPropertiesWithId(uint32_t id) {
+ return pointerProperties[idToIndex[id]];
+ }
+
+ inline bool isHovering(uint32_t pointerIndex) const {
return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id);
}
+
+ inline bool isTouching(uint32_t pointerIndex) const {
+ return touchingIdBits.hasBit(pointerProperties[pointerIndex].id);
+ }
};
@@ -973,9 +1028,12 @@
virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
int32_t token);
virtual void cancelVibrate(int32_t token);
+ virtual void cancelTouch(nsecs_t when);
virtual int32_t getMetaState();
+ virtual void updateExternalStylusState(const StylusState& state);
+
virtual void fadePointer();
protected:
@@ -987,6 +1045,7 @@
static void dumpRawAbsoluteAxisInfo(String8& dump,
const RawAbsoluteAxisInfo& axis, const char* name);
+ static void dumpStylusState(String8& dump, const StylusState& state);
};
@@ -1191,7 +1250,9 @@
const int32_t* keyCodes, uint8_t* outFlags);
virtual void fadePointer();
+ virtual void cancelTouch(nsecs_t when);
virtual void timeoutExpired(nsecs_t when);
+ virtual void updateExternalStylusState(const StylusState& state);
protected:
CursorButtonAccumulator mCursorButtonAccumulator;
@@ -1331,36 +1392,86 @@
// Affine location transformation/calibration
struct TouchAffineTransformation mAffineTransform;
- // Raw pointer axis information from the driver.
RawPointerAxes mRawPointerAxes;
- // Raw pointer sample data.
- RawPointerData mCurrentRawPointerData;
- RawPointerData mLastRawPointerData;
+ struct RawState {
+ nsecs_t when;
- // Cooked pointer sample data.
- CookedPointerData mCurrentCookedPointerData;
- CookedPointerData mLastCookedPointerData;
+ // Raw pointer sample data.
+ RawPointerData rawPointerData;
- // Button state.
- int32_t mCurrentButtonState;
- int32_t mLastButtonState;
+ int32_t buttonState;
- // Scroll state.
- int32_t mCurrentRawVScroll;
- int32_t mCurrentRawHScroll;
+ // Scroll state.
+ int32_t rawVScroll;
+ int32_t rawHScroll;
- // Id bits used to differentiate fingers, stylus and mouse tools.
- BitSet32 mCurrentFingerIdBits; // finger or unknown
- BitSet32 mLastFingerIdBits;
- BitSet32 mCurrentStylusIdBits; // stylus or eraser
- BitSet32 mLastStylusIdBits;
- BitSet32 mCurrentMouseIdBits; // mouse or lens
- BitSet32 mLastMouseIdBits;
+ void copyFrom(const RawState& other) {
+ when = other.when;
+ rawPointerData.copyFrom(other.rawPointerData);
+ buttonState = other.buttonState;
+ rawVScroll = other.rawVScroll;
+ rawHScroll = other.rawHScroll;
+ }
+
+ void clear() {
+ when = 0;
+ rawPointerData.clear();
+ buttonState = 0;
+ rawVScroll = 0;
+ rawHScroll = 0;
+ }
+ };
+
+ struct CookedState {
+ // Cooked pointer sample data.
+ CookedPointerData cookedPointerData;
+
+ // Id bits used to differentiate fingers, stylus and mouse tools.
+ BitSet32 fingerIdBits;
+ BitSet32 stylusIdBits;
+ BitSet32 mouseIdBits;
+
+ int32_t buttonState;
+
+ void copyFrom(const CookedState& other) {
+ cookedPointerData.copyFrom(other.cookedPointerData);
+ fingerIdBits = other.fingerIdBits;
+ stylusIdBits = other.stylusIdBits;
+ mouseIdBits = other.mouseIdBits;
+ buttonState = other.buttonState;
+ }
+
+ void clear() {
+ cookedPointerData.clear();
+ fingerIdBits.clear();
+ stylusIdBits.clear();
+ mouseIdBits.clear();
+ buttonState = 0;
+ }
+ };
+
+ Vector<RawState> mRawStatesPending;
+ RawState mCurrentRawState;
+ CookedState mCurrentCookedState;
+ RawState mLastRawState;
+ CookedState mLastCookedState;
+
+ // State provided by an external stylus
+ StylusState mExternalStylusState;
+ int64_t mExternalStylusId;
+ nsecs_t mExternalStylusFusionTimeout;
+ bool mExternalStylusDataPending;
// True if we sent a HOVER_ENTER event.
bool mSentHoverEnter;
+ // Have we assigned pointer IDs for this stream
+ bool mHavePointerIds;
+
+ // Is the current stream of direct touch events aborted
+ bool mCurrentMotionAborted;
+
// The time the primary pointer last went down.
nsecs_t mDownTime;
@@ -1380,11 +1491,13 @@
virtual void parseCalibration();
virtual void resolveCalibration();
virtual void dumpCalibration(String8& dump);
- virtual void dumpAffineTransformation(String8& dump);
- virtual bool hasStylus() const = 0;
virtual void updateAffineTransformation();
+ virtual void dumpAffineTransformation(String8& dump);
+ virtual void resolveExternalStylusPresence();
+ virtual bool hasStylus() const = 0;
+ virtual bool hasExternalStylus() const;
- virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0;
+ virtual void syncTouch(nsecs_t when, RawState* outState) = 0;
private:
// The current viewport.
@@ -1430,6 +1543,8 @@
float mTiltYCenter;
float mTiltYScale;
+ bool mExternalStylusConnected;
+
// Oriented motion ranges for input device info.
struct OrientedRanges {
InputDeviceInfo::MotionRange x;
@@ -1672,16 +1787,25 @@
VelocityControl mWheelXVelocityControl;
VelocityControl mWheelYVelocityControl;
+ void resetExternalStylus();
+ void clearStylusDataPendingFlags();
+
void sync(nsecs_t when);
bool consumeRawTouches(nsecs_t when, uint32_t policyFlags);
+ void processRawTouches(bool timeout);
+ void cookAndDispatch(nsecs_t when);
void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
int32_t keyEventAction, int32_t keyEventFlags);
void dispatchTouches(nsecs_t when, uint32_t policyFlags);
void dispatchHoverExit(nsecs_t when, uint32_t policyFlags);
void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags);
+ void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags);
+ void dispatchButtonPress(nsecs_t when, uint32_t policyFlags);
+ const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData);
void cookPointerData();
+ void abortTouches(nsecs_t when, uint32_t policyFlags);
void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage);
void abortPointerUsage(nsecs_t when, uint32_t policyFlags);
@@ -1702,13 +1826,17 @@
bool down, bool hovering);
void abortPointerSimple(nsecs_t when, uint32_t policyFlags);
+ bool assignExternalStylusId(const RawState& state, bool timeout);
+ void applyExternalStylusButtonState(nsecs_t when);
+ void applyExternalStylusTouchState(nsecs_t when);
+
// Dispatches a motion event.
// If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
// method will take care of setting the index and transmuting the action to DOWN or UP
// it is the first / last pointer to go down / up.
void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
- int32_t edgeFlags,
+ int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
@@ -1723,7 +1851,7 @@
bool isPointInsideSurface(int32_t x, int32_t y);
const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
- void assignPointerIds();
+ static void assignPointerIds(const RawState* last, RawState* current);
};
@@ -1736,7 +1864,7 @@
virtual void process(const RawEvent* rawEvent);
protected:
- virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
+ virtual void syncTouch(nsecs_t when, RawState* outState);
virtual void configureRawPointerAxes();
virtual bool hasStylus() const;
@@ -1754,7 +1882,7 @@
virtual void process(const RawEvent* rawEvent);
protected:
- virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
+ virtual void syncTouch(nsecs_t when, RawState* outState);
virtual void configureRawPointerAxes();
virtual bool hasStylus() const;
@@ -1766,6 +1894,27 @@
int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1];
};
+class ExternalStylusInputMapper : public InputMapper {
+public:
+ ExternalStylusInputMapper(InputDevice* device);
+ virtual ~ExternalStylusInputMapper() = default;
+
+ virtual uint32_t getSources();
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
+ virtual void reset(nsecs_t when);
+ virtual void process(const RawEvent* rawEvent);
+ virtual void sync(nsecs_t when);
+
+private:
+ SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
+ RawAbsoluteAxisInfo mRawPressureAxis;
+ TouchButtonAccumulator mTouchButtonAccumulator;
+
+ StylusState mStylusState;
+};
+
class JoystickInputMapper : public InputMapper {
public:
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
new file mode 100644
index 0000000..b828175
--- /dev/null
+++ b/services/inputflinger/host/Android.mk
@@ -0,0 +1,62 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+ InputFlinger.cpp \
+ InputDriver.cpp \
+ InputHost.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libcrypto \
+ libcutils \
+ libinput \
+ liblog \
+ libutils \
+ libhardware
+
+
+# TODO: Move inputflinger to its own process and mark it hidden
+#LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_MODULE := libinputflingerhost
+
+include $(BUILD_SHARED_LIBRARY)
+
+########################################################################
+# build input flinger executable
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+ main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libinputflingerhost \
+ libutils
+
+LOCAL_MODULE := inputflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
new file mode 100644
index 0000000..630a596
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 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 <stdint.h>
+#include <sys/types.h>
+
+#define LOG_TAG "InputDriver"
+
+#define LOG_NDEBUG 0
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT2 " "
+
+namespace android {
+
+static input_host_callbacks_t kCallbacks = {
+ .create_device_identifier = create_device_identifier,
+ .create_device_definition = create_device_definition,
+ .create_input_report_definition = create_input_report_definition,
+ .create_output_report_definition = create_output_report_definition,
+ .input_device_definition_add_report = input_device_definition_add_report,
+ .input_report_definition_add_collection = input_report_definition_add_collection,
+ .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int,
+ .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool,
+ .register_device = register_device,
+ .input_allocate_report = input_allocate_report,
+ .input_report_set_usage_int = input_report_set_usage_int,
+ .input_report_set_usage_bool = input_report_set_usage_bool,
+ .report_event = report_event,
+ .input_get_device_property_map = input_get_device_property_map,
+ .input_get_device_property = input_get_device_property,
+ .input_get_property_key = input_get_property_key,
+ .input_get_property_value = input_get_property_value,
+ .input_free_device_property = input_free_device_property,
+ .input_free_device_property_map = input_free_device_property_map,
+};
+
+InputDriver::InputDriver(const char* name) : mName(String8(name)) {
+ const hw_module_t* module;
+ int err = input_open(&module, name);
+ LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name);
+ mHal = reinterpret_cast<const input_module_t*>(module);
+}
+
+void InputDriver::init(InputHostInterface* host) {
+ mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks);
+}
+
+void InputDriver::dump(String8& result) {
+ result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string());
+}
+
+
+// HAL wrapper functions
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+ const char* name, int32_t product_id, int32_t vendor_id,
+ input_bus_t bus, const char* unique_id) {
+ return nullptr;
+}
+
+input_device_definition_t* create_device_definition(input_host_t* host) {
+ return nullptr;
+}
+
+input_report_definition_t* create_input_report_definition(input_host_t* host) {
+ return nullptr;
+}
+
+input_report_definition_t* create_output_report_definition(input_host_t* host) {
+ return nullptr;
+}
+
+void input_device_definition_add_report(input_host_t* host,
+ input_device_definition_t* d, input_report_definition_t* r) { }
+
+void input_report_definition_add_collection(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id, int32_t arity) { }
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t usage, int32_t min, int32_t max, float resolution) { }
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t* usage, size_t usage_count) { }
+
+
+input_device_handle_t* register_device(input_host_t* host,
+ input_device_identifier_t* id, input_device_definition_t* d) {
+ return nullptr;
+}
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) {
+ return nullptr;
+}
+void input_report_set_usage_int(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { }
+
+void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { }
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { }
+
+input_property_map_t* input_get_device_property_map(input_host_t* host,
+ input_device_identifier_t* id) {
+ return nullptr;
+}
+
+input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
+ const char* key) {
+ return nullptr;
+}
+
+const char* input_get_property_key(input_host_t* host, input_property_t* property) {
+ return nullptr;
+}
+
+const char* input_get_property_value(input_host_t* host, input_property_t* property) {
+ return nullptr;
+}
+
+void input_free_device_property(input_host_t* host, input_property_t* property) { }
+
+void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { }
+
+} // namespace android
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
new file mode 100644
index 0000000..7734ac2
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_INPUT_DRIVER_H
+#define ANDROID_INPUT_DRIVER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class InputHostInterface;
+
+class InputDriverInterface : public virtual RefBase {
+protected:
+ InputDriverInterface() = default;
+ virtual ~InputDriverInterface() = default;
+
+public:
+ virtual void init(InputHostInterface* host) = 0;
+
+ virtual void dump(String8& result) = 0;
+};
+
+class InputDriver : public InputDriverInterface {
+public:
+ InputDriver(const char* name);
+ virtual ~InputDriver() = default;
+
+ virtual void init(InputHostInterface* host) override;
+
+ virtual void dump(String8& result) override;
+
+private:
+ String8 mName;
+ const input_module_t* mHal;
+};
+
+
+extern "C" {
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+ const char* name, int32_t product_id, int32_t vendor_id,
+ input_bus_t bus, const char* unique_id);
+
+input_device_definition_t* create_device_definition(input_host_t* host);
+
+input_report_definition_t* create_input_report_definition(input_host_t* host);
+
+input_report_definition_t* create_output_report_definition(input_host_t* host);
+
+void input_device_definition_add_report(input_host_t* host,
+ input_device_definition_t* d, input_report_definition_t* r);
+
+void input_report_definition_add_collection(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id, int32_t arity);
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t usage, int32_t min, int32_t max, float resolution);
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t* usage, size_t usage_count);
+
+
+input_device_handle_t* register_device(input_host_t* host,
+ input_device_identifier_t* id, input_device_definition_t* d);
+
+void unregister_device(input_host_t* host, input_device_handle_t* handle);
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r);
+
+void input_report_set_usage_int(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index);
+
+void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index);
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report);
+
+input_property_map_t* input_get_device_property_map(input_host_t* host,
+ input_device_identifier_t* id);
+
+input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
+ const char* key);
+
+const char* input_get_property_key(input_host_t* host, input_property_t* property);
+
+const char* input_get_property_value(input_host_t* host, input_property_t* property);
+
+void input_free_device_property(input_host_t* host, input_property_t* property);
+
+void input_free_device_property_map(input_host_t* host, input_property_map_t* map);
+}
+
+} // namespace android
+#endif // ANDROID_INPUT_DRIVER_H
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
new file mode 100644
index 0000000..859c3b8
--- /dev/null
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "InputFlinger"
+
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+#include "InputFlinger.h"
+#include "InputDriver.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <hardware/input.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER");
+const String16 sDumpPermission("android.permission.DUMP");
+
+
+InputFlinger::InputFlinger() :
+ BnInputFlinger() {
+ ALOGI("InputFlinger is starting");
+ mHost = new InputHost();
+ mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV));
+}
+
+InputFlinger::~InputFlinger() {
+}
+
+status_t InputFlinger::dump(int fd, const Vector<String16>& args) {
+ String8 result;
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL)
+ && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
+ result.appendFormat("Permission Denial: "
+ "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ dumpInternal(result);
+ }
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+void InputFlinger::dumpInternal(String8& result) {
+ result.append("INPUT FLINGER (dumpsys inputflinger)\n");
+ mHost->dump(result);
+}
+
+}; // namespace android
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
new file mode 100644
index 0000000..39e69e5
--- /dev/null
+++ b/services/inputflinger/host/InputFlinger.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_INPUT_FLINGER_H
+#define ANDROID_INPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "InputHost.h"
+
+#include <cutils/compiler.h>
+#include <input/IInputFlinger.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class InputFlinger : public BnInputFlinger {
+public:
+ static char const* getServiceName() ANDROID_API {
+ return "inputflinger";
+ }
+
+ InputFlinger() ANDROID_API;
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ virtual ~InputFlinger();
+
+ void dumpInternal(String8& result);
+
+ sp<InputHostInterface> mHost;
+};
+
+} // namespace android
+
+#endif // ANDROID_INPUT_FLINGER_H
diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp
new file mode 100644
index 0000000..51d3e6b
--- /dev/null
+++ b/services/inputflinger/host/InputHost.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 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 <vector>
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT " "
+
+namespace android {
+
+void InputHost::registerInputDriver(InputDriverInterface* driver) {
+ LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!");
+ driver->init(this);
+ mDrivers.push_back(driver);
+}
+
+void InputHost::dump(String8& result) {
+ result.append(INDENT "Input Drivers:\n");
+ for (size_t i = 0; i < mDrivers.size(); i++) {
+ mDrivers[i]->dump(result);
+ }
+}
+
+} // namespace android
diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h
new file mode 100644
index 0000000..42a66e0
--- /dev/null
+++ b/services/inputflinger/host/InputHost.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_INPUT_HOST_H
+#define ANDROID_INPUT_HOST_H
+
+#include <vector>
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+#include "InputDriver.h"
+
+// Declare a concrete type for the HAL
+struct input_host {
+};
+
+namespace android {
+
+class InputDriverInterface;
+
+class InputHostInterface : public input_host_t, public virtual RefBase {
+protected:
+ InputHostInterface() = default;
+ virtual ~InputHostInterface() = default;
+
+public:
+
+ virtual void registerInputDriver(InputDriverInterface* driver) = 0;
+
+ virtual void dump(String8& result) = 0;
+};
+
+class InputHost : public InputHostInterface {
+public:
+ InputHost() = default;
+
+ virtual void registerInputDriver(InputDriverInterface* driver) override;
+
+ virtual void dump(String8& result) override;
+
+private:
+ std::vector<sp<InputDriverInterface>> mDrivers;
+};
+
+} // namespace android
+#endif // ANDRIOD_INPUT_HOST_H
diff --git a/services/inputflinger/host/main.cpp b/services/inputflinger/host/main.cpp
new file mode 100644
index 0000000..0a517cc
--- /dev/null
+++ b/services/inputflinger/host/main.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 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 <binder/BinderService.h>
+#include "InputFlinger.h"
+
+using namespace android;
+
+int main(int, char**) {
+ ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ BinderService<InputFlinger>::publishAndJoinThreadPool(true);
+ return 0;
+}
diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk
index 0742a08..4c43392 100644
--- a/services/inputflinger/tests/Android.mk
+++ b/services/inputflinger/tests/Android.mk
@@ -10,7 +10,6 @@
shared_libraries := \
libcutils \
liblog \
- libandroidfw \
libutils \
libhardware \
libhardware_legacy \
@@ -24,7 +23,7 @@
external/skia/include/core
-module_tags := eng tests
+module_tags := tests
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 9b68986..2d8eaef 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -150,7 +150,7 @@
// Rejects undefined motion actions.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -161,7 +161,7 @@
// Rejects pointer down with invalid index.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -171,7 +171,7 @@
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -182,7 +182,7 @@
// Rejects pointer up with invalid index.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -192,7 +192,7 @@
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -202,7 +202,7 @@
// Rejects motion events with invalid number of pointers.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -211,7 +211,7 @@
<< "Should reject motion events with 0 pointers.";
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -222,7 +222,7 @@
// Rejects motion events with invalid pointer ids.
pointerProperties[0].id = -1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -232,7 +232,7 @@
pointerProperties[0].id = MAX_POINTER_ID + 1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -244,7 +244,7 @@
pointerProperties[0].id = 1;
pointerProperties[1].id = 1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 40f51b6..f34b810 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -777,6 +777,14 @@
virtual int32_t bumpGeneration() {
return ++mGeneration;
}
+
+ virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+
+ }
+
+ virtual void dispatchExternalStylusState(const StylusState&) {
+
+ }
};
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index cb962a6..81f32cd 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -83,7 +83,7 @@
if (mBatteryStatService != 0) {
Mutex::Autolock _l(mActivationsLock);
int64_t identity = IPCThreadState::self()->clearCallingIdentity();
- for (ssize_t i=0 ; i<mActivations.size() ; i++) {
+ for (size_t i=0 ; i<mActivations.size() ; i++) {
const Info& info(mActivations[i]);
if (info.uid == uid) {
mBatteryStatService->noteStopSensor(info.uid, info.handle);
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 3cb3745..61118bc 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -44,7 +44,6 @@
bool GravitySensor::process(sensors_event_t* outEvent,
const sensors_event_t& event)
{
- const static double NS2S = 1.0 / 1000000000.0;
if (event.type == SENSOR_TYPE_ACCELEROMETER) {
vec3_t g;
if (!mSensorFusion.hasEstimate())
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 80845a2..40d596f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -79,16 +79,17 @@
sensor_t const* list;
ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
- result.appendFormat("halVersion %d\n", getHalDeviceVersion());
+ result.appendFormat("halVersion 0x%08x\n", getHalDeviceVersion());
result.appendFormat("%d h/w sensors:\n", int(count));
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i<size_t(count) ; i++) {
const Info& info = mActivationCount.valueFor(list[i].handle);
+ if (info.batchParams.isEmpty()) continue;
result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle,
info.batchParams.size());
for (size_t j = 0; j < info.batchParams.size(); j++) {
- BatchParams params = info.batchParams.valueAt(j);
+ const BatchParams& params = info.batchParams.valueAt(j);
result.appendFormat("%4.1f%s", params.batchDelay / 1e6f,
j < info.batchParams.size() - 1 ? ", " : "");
}
@@ -147,8 +148,12 @@
if (enabled) {
ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
+ if (isClientDisabledLocked(ident)) {
+ return INVALID_OPERATION;
+ }
+
if (info.batchParams.indexOfKey(ident) >= 0) {
- if (info.batchParams.size() == 1) {
+ if (info.numActiveClients() == 1) {
// This is the first connection, we need to activate the underlying h/w sensor.
actuateHardware = true;
}
@@ -160,7 +165,7 @@
ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
if (info.removeBatchParamsForIdent(ident) >= 0) {
- if (info.batchParams.size() == 0) {
+ if (info.numActiveClients() == 0) {
// This is the last connection, we need to de-activate the underlying h/w sensor.
actuateHardware = true;
} else {
@@ -181,10 +186,15 @@
} else {
// sensor wasn't enabled for this ident
}
+
+ if (isClientDisabledLocked(ident)) {
+ return NO_ERROR;
+ }
}
if (actuateHardware) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
+ enabled);
err = mSensorDevice->activate(
reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled);
ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
@@ -197,7 +207,7 @@
}
// On older devices which do not support batch, call setDelay().
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
info.bestBatchParams.batchDelay);
mSensorDevice->setDelay(
@@ -279,6 +289,7 @@
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
Mutex::Autolock _l(mLock);
+ if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
Info& info( mActivationCount.editValueFor(handle) );
// If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
// Calling setDelay() in batch mode is an invalid operation.
@@ -298,7 +309,6 @@
int SensorDevice::getHalDeviceVersion() const {
if (!mSensorDevice) return -1;
-
return mSensorDevice->common.version;
}
@@ -306,12 +316,110 @@
if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
return INVALID_OPERATION;
}
+ if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return mSensorDevice->flush(mSensorDevice, handle);
}
+bool SensorDevice::isClientDisabled(void* ident) {
+ Mutex::Autolock _l(mLock);
+ return isClientDisabledLocked(ident);
+}
+
+bool SensorDevice::isClientDisabledLocked(void* ident) {
+ return mDisabledClients.indexOf(ident) >= 0;
+}
+
+void SensorDevice::enableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ mDisabledClients.clear();
+ const int halVersion = getHalDeviceVersion();
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ Info& info = mActivationCount.editValueAt(i);
+ if (info.batchParams.isEmpty()) continue;
+ info.selectBatchParams();
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
+ sensor_handle);
+ status_t err(NO_ERROR);
+ if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
+ err = mSensorDevice->batch(mSensorDevice, sensor_handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (err == NO_ERROR) {
+ err = mSensorDevice->activate(
+ reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+ sensor_handle, 1);
+ ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
+ err = mSensorDevice->setDelay(
+ reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+ sensor_handle, info.bestBatchParams.batchDelay);
+ ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+ }
+}
+
+void SensorDevice::disableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ const Info& info = mActivationCount.valueAt(i);
+ // Check if this sensor has been activated previously and disable it.
+ if (info.batchParams.size() > 0) {
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
+ sensor_handle);
+ mSensorDevice->activate(
+ reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
+ sensor_handle, 0);
+ // Add all the connections that were registered for this sensor to the disabled
+ // clients list.
+ for (size_t j = 0; j < info.batchParams.size(); ++j) {
+ mDisabledClients.add(info.batchParams.keyAt(j));
+ }
+ }
+ }
+}
+
+status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) {
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor,
+ injected_sensor_event->timestamp, injected_sensor_event->data[0],
+ injected_sensor_event->data[1], injected_sensor_event->data[2],
+ injected_sensor_event->data[3], injected_sensor_event->data[4],
+ injected_sensor_event->data[5]);
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+ return INVALID_OPERATION;
+ }
+ return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event);
+}
+
+status_t SensorDevice::setMode(uint32_t mode) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+ return INVALID_OPERATION;
+ }
+ return mSensorModule->set_operation_mode(mode);
+}
+
// ---------------------------------------------------------------------------
+int SensorDevice::Info::numActiveClients() {
+ SensorDevice& device(SensorDevice::getInstance());
+ int num = 0;
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
+ ++num;
+ }
+ }
+ return num;
+}
+
status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
@@ -329,19 +437,16 @@
}
void SensorDevice::Info::selectBatchParams() {
- BatchParams bestParams(-1, -1, -1);
+ BatchParams bestParams(0, -1, -1);
+ SensorDevice& device(SensorDevice::getInstance());
- if (batchParams.size() > 0) {
- BatchParams params = batchParams.valueAt(0);
- bestParams = params;
- }
-
- for (size_t i = 1; i < batchParams.size(); ++i) {
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
BatchParams params = batchParams.valueAt(i);
- if (params.batchDelay < bestParams.batchDelay) {
+ if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
bestParams.batchDelay = params.batchDelay;
}
- if (params.batchTimeout < bestParams.batchTimeout) {
+ if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
bestParams.batchTimeout = params.batchTimeout;
}
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 761b48c..c484849 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -42,6 +42,7 @@
// Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from
// batch call. For continous mode clients, maxBatchReportLatency is set to zero.
struct BatchParams {
+ // TODO: Get rid of flags parameter everywhere.
int flags;
nsecs_t batchDelay, batchTimeout;
BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {}
@@ -65,7 +66,7 @@
// requested by the client.
KeyedVector<void*, BatchParams> batchParams;
- Info() : bestBatchParams(-1, -1, -1) {}
+ Info() : bestBatchParams(0, -1, -1) {}
// Sets batch parameters for this ident. Returns error if this ident is not already present
// in the KeyedVector above.
status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs,
@@ -75,10 +76,17 @@
// Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of
// the removed ident. If index >=0, ident is present and successfully removed.
ssize_t removeBatchParamsForIdent(void* ident);
+
+ int numActiveClients();
};
DefaultKeyedVector<int, Info> mActivationCount;
+ // Use this vector to determine which client is activated or deactivated.
+ SortedVector<void *> mDisabledClients;
SensorDevice();
+
+ bool isClientDisabled(void* ident);
+ bool isClientDisabledLocked(void* ident);
public:
ssize_t getSensorList(sensor_t const** list);
status_t initCheck() const;
@@ -90,7 +98,11 @@
// Call batch with timeout zero instead of calling setDelay() for newer devices.
status_t setDelay(void* ident, int handle, int64_t ns);
status_t flush(void* ident, int handle);
+ status_t setMode(uint32_t mode);
+ void disableAllSensors();
+ void enableAllSensors();
void autoDisable(void *ident, int handle);
+ status_t injectSensorData(const sensors_event_t *event);
void dump(String8& result);
};
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index a857366..1a486a3 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -31,6 +31,7 @@
#include <utils/Singleton.h>
#include <utils/String16.h>
+#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
@@ -63,7 +64,9 @@
*
*/
-const char* SensorService::WAKE_LOCK_NAME = "SensorService";
+const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock";
+// Permissions.
+static const String16 sDump("android.permission.DUMP");
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
@@ -74,7 +77,6 @@
void SensorService::onFirstRef()
{
ALOGD("nuSensorService starting...");
-
SensorDevice& dev(SensorDevice::getInstance());
if (dev.initCheck() == NO_ERROR) {
@@ -82,7 +84,7 @@
ssize_t count = dev.getSensorList(&list);
if (count > 0) {
ssize_t orientationIndex = -1;
- bool hasGyro = false;
+ bool hasGyro = false, hasAccel = false, hasMag = false;
uint32_t virtualSensorsNeeds =
(1<<SENSOR_TYPE_GRAVITY) |
(1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
@@ -92,6 +94,12 @@
for (ssize_t i=0 ; i<count ; i++) {
registerSensor( new HardwareSensor(list[i]) );
switch (list[i].type) {
+ case SENSOR_TYPE_ACCELEROMETER:
+ hasAccel = true;
+ break;
+ case SENSOR_TYPE_MAGNETIC_FIELD:
+ hasMag = true;
+ break;
case SENSOR_TYPE_ORIENTATION:
orientationIndex = i;
break;
@@ -110,12 +118,12 @@
// it's safe to instantiate the SensorFusion object here
// (it wants to be instantiated after h/w sensors have been
// registered)
- const SensorFusion& fusion(SensorFusion::getInstance());
+ SensorFusion::getInstance();
// build the sensor list returned to users
mUserSensorList = mSensorList;
- if (hasGyro) {
+ if (hasGyro && hasAccel && hasMag) {
Sensor aSensor;
// Add Android virtual sensors if they're not already
@@ -154,7 +162,7 @@
// Check if the device really supports batching by looking at the FIFO event
// counts for each sensor.
bool batchingSupported = false;
- for (int i = 0; i < mSensorList.size(); ++i) {
+ for (size_t i = 0; i < mSensorList.size(); ++i) {
if (mSensorList[i].getFifoMaxEventCount() > 0) {
batchingSupported = true;
break;
@@ -190,10 +198,16 @@
mSensorEventBuffer = new sensors_event_t[minBufferSize];
mSensorEventScratch = new sensors_event_t[minBufferSize];
mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize];
+ mCurrentOperatingMode = NORMAL;
+ mNextSensorRegIndex = 0;
+ for (int i = 0; i < SENSOR_REGISTRATIONS_BUF_SIZE; ++i) {
+ mLastNSensorRegistrations.push();
+ }
+
+ mInitCheck = NO_ERROR;
mAckReceiver = new SensorEventAckReceiver(this);
mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY);
- mInitCheck = NO_ERROR;
run("SensorService", PRIORITY_URGENT_DISPLAY);
}
}
@@ -210,7 +224,7 @@
// add to our handle->SensorInterface mapping
mSensorMap.add(sensor.getHandle(), s);
// create an entry in the mLastEventSeen array
- mLastEventSeen.add(sensor.getHandle(), event);
+ mLastEventSeen.add(sensor.getHandle(), NULL);
return sensor;
}
@@ -228,9 +242,7 @@
delete mSensorMap.valueAt(i);
}
-static const String16 sDump("android.permission.DUMP");
-
-status_t SensorService::dump(int fd, const Vector<String16>& /*args*/)
+status_t SensorService::dump(int fd, const Vector<String16>& args)
{
String8 result;
if (!PermissionCache::checkCallingPermission(sDump)) {
@@ -239,116 +251,188 @@
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
} else {
+ if (args.size() > 2) {
+ return INVALID_OPERATION;
+ }
Mutex::Autolock _l(mLock);
- result.append("Sensor List:\n");
- for (size_t i=0 ; i<mSensorList.size() ; i++) {
- const Sensor& s(mSensorList[i]);
- const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
- result.appendFormat(
- "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
- s.getName().string(),
- s.getVendor().string(),
- s.getVersion(),
- s.getStringType().string(),
- s.getHandle(),
- s.getRequiredPermission().string(),
- s.getType());
-
- const int reportingMode = s.getReportingMode();
- if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
- result.append(" continuous | ");
- } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
- result.append(" on-change | ");
- } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
- result.append(" one-shot | ");
+ SensorDevice& dev(SensorDevice::getInstance());
+ if (args.size() == 2 && args[0] == String16("restrict")) {
+ // If already in restricted mode. Ignore.
+ if (mCurrentOperatingMode == RESTRICTED) {
+ return status_t(NO_ERROR);
+ }
+ // If in any mode other than normal, ignore.
+ if (mCurrentOperatingMode != NORMAL) {
+ return INVALID_OPERATION;
+ }
+ mCurrentOperatingMode = RESTRICTED;
+ dev.disableAllSensors();
+ // Clear all pending flush connections for all active sensors. If one of the active
+ // connections has called flush() and the underlying sensor has been disabled before a
+ // flush complete event is returned, we need to remove the connection from this queue.
+ for (size_t i=0 ; i< mActiveSensors.size(); ++i) {
+ mActiveSensors.valueAt(i)->clearAllPendingFlushConnections();
+ }
+ mWhiteListedPackage.setTo(String8(args[1]));
+ return status_t(NO_ERROR);
+ } else if (args.size() == 1 && args[0] == String16("enable")) {
+ // If currently in restricted mode, reset back to NORMAL mode else ignore.
+ if (mCurrentOperatingMode == RESTRICTED) {
+ mCurrentOperatingMode = NORMAL;
+ dev.enableAllSensors();
+ }
+ if (mCurrentOperatingMode == DATA_INJECTION) {
+ resetToNormalModeLocked();
+ }
+ mWhiteListedPackage.clear();
+ return status_t(NO_ERROR);
+ } else if (args.size() == 2 && args[0] == String16("data_injection")) {
+ if (mCurrentOperatingMode == NORMAL) {
+ dev.disableAllSensors();
+ status_t err = dev.setMode(DATA_INJECTION);
+ if (err == NO_ERROR) {
+ mCurrentOperatingMode = DATA_INJECTION;
+ } else {
+ // Re-enable sensors.
+ dev.enableAllSensors();
+ }
+ mWhiteListedPackage.setTo(String8(args[1]));
+ return NO_ERROR;
+ } else if (mCurrentOperatingMode == DATA_INJECTION) {
+ // Already in DATA_INJECTION mode. Treat this as a no_op.
+ return NO_ERROR;
} else {
- result.append(" special-trigger | ");
+ // Transition to data injection mode supported only from NORMAL mode.
+ return INVALID_OPERATION;
+ }
+ } else if (mSensorList.size() == 0) {
+ result.append("No Sensors on the device\n");
+ } else {
+ // Default dump the sensor list and debugging information.
+ result.append("Sensor List:\n");
+ for (size_t i=0 ; i<mSensorList.size() ; i++) {
+ const Sensor& s(mSensorList[i]);
+ result.appendFormat(
+ "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
+ s.getName().string(),
+ s.getVendor().string(),
+ s.getVersion(),
+ s.getStringType().string(),
+ s.getHandle(),
+ s.getRequiredPermission().string(),
+ s.getType());
+
+ const int reportingMode = s.getReportingMode();
+ if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
+ result.append(" continuous | ");
+ } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
+ result.append(" on-change | ");
+ } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
+ result.append(" one-shot | ");
+ } else {
+ result.append(" special-trigger | ");
+ }
+
+ if (s.getMaxDelay() > 0) {
+ result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
+ } else {
+ result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+ }
+
+ if (s.getMinDelay() > 0) {
+ result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
+ } else {
+ result.appendFormat("minDelay=%dus |", s.getMinDelay());
+ }
+
+ if (s.getFifoMaxEventCount() > 0) {
+ result.appendFormat("FifoMax=%d events | ",
+ s.getFifoMaxEventCount());
+ } else {
+ result.append("no batching | ");
+ }
+
+ if (s.isWakeUpSensor()) {
+ result.appendFormat("wakeUp | ");
+ } else {
+ result.appendFormat("non-wakeUp | ");
+ }
+
+ int bufIndex = mLastEventSeen.indexOfKey(s.getHandle());
+ if (bufIndex >= 0) {
+ const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex);
+ if (buf != NULL && s.getRequiredPermission().isEmpty()) {
+ buf->printBuffer(result);
+ } else {
+ result.append("last=<> \n");
+ }
+ }
+ result.append("\n");
+ }
+ SensorFusion::getInstance().dump(result);
+ SensorDevice::getInstance().dump(result);
+
+ result.append("Active sensors:\n");
+ for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+ int handle = mActiveSensors.keyAt(i);
+ result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
+ getSensorName(handle).string(),
+ handle,
+ mActiveSensors.valueAt(i)->getNumConnections());
}
- if (s.getMaxDelay() > 0) {
- result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
- } else {
- result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+ result.appendFormat("Socket Buffer size = %zd events\n",
+ mSocketBufferSize/sizeof(sensors_event_t));
+ result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" :
+ "not held");
+ result.appendFormat("Mode :");
+ switch(mCurrentOperatingMode) {
+ case NORMAL:
+ result.appendFormat(" NORMAL\n");
+ break;
+ case RESTRICTED:
+ result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string());
+ break;
+ case DATA_INJECTION:
+ result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string());
+ }
+ result.appendFormat("%zd active connections\n", mActiveConnections.size());
+
+ for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
+ sp<SensorEventConnection> connection(mActiveConnections[i].promote());
+ if (connection != 0) {
+ result.appendFormat("Connection Number: %zu \n", i);
+ connection->dump(result);
+ }
}
- if (s.getMinDelay() > 0) {
- result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
- } else {
- result.appendFormat("minDelay=%dus |", s.getMinDelay());
- }
-
- if (s.getFifoMaxEventCount() > 0) {
- result.appendFormat("FifoMax=%d events | ",
- s.getFifoMaxEventCount());
- } else {
- result.append("no batching | ");
- }
-
- if (s.isWakeUpSensor()) {
- result.appendFormat("wakeUp | ");
- } else {
- result.appendFormat("non-wakeUp | ");
- }
-
- switch (s.getType()) {
- case SENSOR_TYPE_ROTATION_VECTOR:
- case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.timestamp);
- break;
- case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
- case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.data[5],
- e.timestamp);
- break;
- case SENSOR_TYPE_GAME_ROTATION_VECTOR:
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.data[3], e.timestamp);
- break;
- case SENSOR_TYPE_SIGNIFICANT_MOTION:
- case SENSOR_TYPE_STEP_DETECTOR:
- result.appendFormat( "last=<%f %" PRId64 ">\n", e.data[0], e.timestamp);
- break;
- case SENSOR_TYPE_STEP_COUNTER:
- result.appendFormat( "last=<%" PRIu64 ", %" PRId64 ">\n", e.u64.step_counter,
- e.timestamp);
- break;
- default:
- // default to 3 values
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.timestamp);
- break;
- }
- result.append("\n");
- }
- SensorFusion::getInstance().dump(result);
- SensorDevice::getInstance().dump(result);
-
- result.append("Active sensors:\n");
- for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
- int handle = mActiveSensors.keyAt(i);
- result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
- getSensorName(handle).string(),
- handle,
- mActiveSensors.valueAt(i)->getNumConnections());
- }
-
- result.appendFormat("Socket Buffer size = %d events\n",
- mSocketBufferSize/sizeof(sensors_event_t));
- result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held");
- result.appendFormat("%zd active connections\n", mActiveConnections.size());
-
- for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != 0) {
- result.appendFormat("Connection Number: %zu \n", i);
- connection->dump(result);
- }
+ result.appendFormat("Previous Registrations:\n");
+ // Log in the reverse chronological order.
+ int currentIndex = (mNextSensorRegIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+ SENSOR_REGISTRATIONS_BUF_SIZE;
+ const int startIndex = currentIndex;
+ do {
+ const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[currentIndex];
+ if (SensorRegistrationInfo::isSentinel(reg_info)) {
+ // Ignore sentinel, proceed to next item.
+ currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+ SENSOR_REGISTRATIONS_BUF_SIZE;
+ continue;
+ }
+ if (reg_info.mActivated) {
+ result.appendFormat("%02d:%02d:%02d activated package=%s handle=0x%08x "
+ "samplingRate=%dus maxReportLatency=%dus\n",
+ reg_info.mHour, reg_info.mMin, reg_info.mSec,
+ reg_info.mPackageName.string(), reg_info.mSensorHandle,
+ reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs);
+ } else {
+ result.appendFormat("%02d:%02d:%02d de-activated package=%s handle=0x%08x\n",
+ reg_info.mHour, reg_info.mMin, reg_info.mSec,
+ reg_info.mPackageName.string(), reg_info.mSensorHandle);
+ }
+ currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+ SENSOR_REGISTRATIONS_BUF_SIZE;
+ } while(startIndex != currentIndex);
}
}
write(fd, result.string(), result.size());
@@ -371,8 +455,9 @@
sensor->autoDisable(connection.get(), handle);
cleanupWithoutDisableLocked(connection, handle);
}
+
}
- }
+ }
}
bool SensorService::threadLoop()
@@ -554,7 +639,6 @@
}
}
-
bool SensorService::isWakeLockAcquired() {
Mutex::Autolock _l(mLock);
return mWakeLockAcquired;
@@ -577,19 +661,15 @@
void SensorService::recordLastValueLocked(
const sensors_event_t* buffer, size_t count) {
- const sensors_event_t* last = NULL;
for (size_t i = 0; i < count; i++) {
- const sensors_event_t* event = &buffer[i];
- if (event->type != SENSOR_TYPE_META_DATA) {
- if (last && event->sensor != last->sensor) {
- mLastEventSeen.editValueFor(last->sensor) = *last;
+ if (buffer[i].type != SENSOR_TYPE_META_DATA) {
+ CircularBuffer* &circular_buf = mLastEventSeen.editValueFor(buffer[i].sensor);
+ if (circular_buf == NULL) {
+ circular_buf = new CircularBuffer(buffer[i].type);
}
- last = event;
+ circular_buf->addEvent(buffer[i]);
}
}
- if (last) {
- mLastEventSeen.editValueFor(last->sensor) = *last;
- }
}
void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
@@ -630,12 +710,11 @@
return sensor != NULL && sensor->getSensor().isWakeUpSensor();
}
-
SensorService::SensorRecord * SensorService::getSensorRecord(int handle) {
return mActiveSensors.valueFor(handle);
}
-Vector<Sensor> SensorService::getSensorList()
+Vector<Sensor> SensorService::getSensorList(const String16& opPackageName)
{
char value[PROPERTY_VALUE_MAX];
property_get("debug.sensors", value, "0");
@@ -644,24 +723,65 @@
Vector<Sensor> accessibleSensorList;
for (size_t i = 0; i < initialSensorList.size(); i++) {
Sensor sensor = initialSensorList[i];
- if (canAccessSensor(sensor)) {
+ if (canAccessSensor(sensor, "getSensorList", opPackageName)) {
accessibleSensorList.add(sensor);
} else {
- ALOGI("Skipped sensor %s because it requires permission %s",
+ ALOGI("Skipped sensor %s because it requires permission %s and app op %d",
sensor.getName().string(),
- sensor.getRequiredPermission().string());
+ sensor.getRequiredPermission().string(),
+ sensor.getRequiredAppOp());
}
}
return accessibleSensorList;
}
-sp<ISensorEventConnection> SensorService::createSensorEventConnection()
-{
+sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName,
+ int requestedMode, const String16& opPackageName) {
+ // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.
+ if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
+ return NULL;
+ }
+
+ Mutex::Autolock _l(mLock);
+ // To create a client in DATA_INJECTION mode to inject data, SensorService should already be
+ // operating in DI mode.
+ if (requestedMode == DATA_INJECTION) {
+ if (mCurrentOperatingMode != DATA_INJECTION) return NULL;
+ if (!isWhiteListedPackage(packageName)) return NULL;
+ }
+
uid_t uid = IPCThreadState::self()->getCallingUid();
- sp<SensorEventConnection> result(new SensorEventConnection(this, uid));
+ sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName,
+ requestedMode == DATA_INJECTION, opPackageName));
+ if (requestedMode == DATA_INJECTION) {
+ if (mActiveConnections.indexOf(result) < 0) {
+ mActiveConnections.add(result);
+ }
+ // Add the associated file descriptor to the Looper for polling whenever there is data to
+ // be injected.
+ result->updateLooperRegistration(mLooper);
+ }
return result;
}
+int SensorService::isDataInjectionEnabled() {
+ Mutex::Autolock _l(mLock);
+ return (mCurrentOperatingMode == DATA_INJECTION);
+}
+
+status_t SensorService::resetToNormalMode() {
+ Mutex::Autolock _l(mLock);
+ return resetToNormalModeLocked();
+}
+
+status_t SensorService::resetToNormalModeLocked() {
+ SensorDevice& dev(SensorDevice::getInstance());
+ dev.enableAllSensors();
+ status_t err = dev.setMode(NORMAL);
+ mCurrentOperatingMode = NORMAL;
+ return err;
+}
+
void SensorService::cleanupConnection(SensorEventConnection* c)
{
Mutex::Autolock _l(mLock);
@@ -708,7 +828,8 @@
}
status_t SensorService::enable(const sp<SensorEventConnection>& connection,
- int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags)
+ int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
+ const String16& opPackageName)
{
if (mInitCheck != NO_ERROR)
return mInitCheck;
@@ -718,11 +839,16 @@
return BAD_VALUE;
}
- if (!verifyCanAccessSensor(sensor->getSensor(), "Tried enabling")) {
+ if (!canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
+ if ((mCurrentOperatingMode == RESTRICTED || mCurrentOperatingMode == DATA_INJECTION)
+ && !isWhiteListedPackage(connection->getPackageName())) {
+ return INVALID_OPERATION;
+ }
+
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec == 0) {
rec = new SensorRecord(connection);
@@ -738,14 +864,24 @@
if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) {
// NOTE: The wake_up flag of this event may get set to
// WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event.
- sensors_event_t& event(mLastEventSeen.editValueFor(handle));
- if (event.version == sizeof(sensors_event_t)) {
- if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
- setWakeLockAcquiredLocked(true);
- }
- connection->sendEvents(&event, 1, NULL);
- if (!connection->needsWakeLock() && mWakeLockAcquired) {
- checkWakeLockStateLocked();
+ CircularBuffer *circular_buf = mLastEventSeen.valueFor(handle);
+ if (circular_buf) {
+ sensors_event_t event;
+ memset(&event, 0, sizeof(event));
+ // It is unlikely that this buffer is empty as the sensor is already active.
+ // One possible corner case may be two applications activating an on-change
+ // sensor at the same time.
+ if(circular_buf->populateLastEvent(&event)) {
+ event.sensor = handle;
+ if (event.version == sizeof(sensors_event_t)) {
+ if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
+ setWakeLockAcquiredLocked(true);
+ }
+ connection->sendEvents(&event, 1, NULL);
+ if (!connection->needsWakeLock() && mWakeLockAcquired) {
+ checkWakeLockStateLocked();
+ }
+ }
}
}
}
@@ -773,7 +909,7 @@
"rate=%" PRId64 " timeout== %" PRId64"",
handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs);
- status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs,
+ status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs,
maxBatchReportLatencyNs);
// Call flush() before calling activate() on the sensor. Wait for a first flush complete
@@ -798,6 +934,19 @@
if (err == NO_ERROR) {
connection->updateLooperRegistration(mLooper);
+ SensorRegistrationInfo ®_info =
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
+ reg_info.mSensorHandle = handle;
+ reg_info.mSamplingRateUs = samplingPeriodNs/1000;
+ reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000;
+ reg_info.mActivated = true;
+ reg_info.mPackageName = connection->getPackageName();
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ reg_info.mHour = timeinfo->tm_hour;
+ reg_info.mMin = timeinfo->tm_min;
+ reg_info.mSec = timeinfo->tm_sec;
+ mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
if (err != NO_ERROR) {
@@ -818,6 +967,20 @@
if (err == NO_ERROR) {
SensorInterface* sensor = mSensorMap.valueFor(handle);
err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
+
+ }
+ if (err == NO_ERROR) {
+ SensorRegistrationInfo ®_info =
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
+ reg_info.mActivated = false;
+ reg_info.mPackageName= connection->getPackageName();
+ reg_info.mSensorHandle = handle;
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ reg_info.mHour = timeinfo->tm_hour;
+ reg_info.mMin = timeinfo->tm_min;
+ reg_info.mSec = timeinfo->tm_sec;
+ mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
return err;
}
@@ -852,7 +1015,7 @@
}
status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection,
- int handle, nsecs_t ns)
+ int handle, nsecs_t ns, const String16& opPackageName)
{
if (mInitCheck != NO_ERROR)
return mInitCheck;
@@ -861,7 +1024,7 @@
if (!sensor)
return BAD_VALUE;
- if (!verifyCanAccessSensor(sensor->getSensor(), "Tried configuring")) {
+ if (!canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) {
return BAD_VALUE;
}
@@ -876,7 +1039,8 @@
return sensor->setDelay(connection.get(), handle, ns);
}
-status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) {
+status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection,
+ const String16& opPackageName) {
if (mInitCheck != NO_ERROR) return mInitCheck;
SensorDevice& dev(SensorDevice::getInstance());
const int halVersion = dev.getHalDeviceVersion();
@@ -896,6 +1060,10 @@
// flush complete event.
connection->incrementPendingFlushCount(handle);
} else {
+ if (!canAccessSensor(sensor->getSensor(), "Tried flushing", opPackageName)) {
+ err = INVALID_OPERATION;
+ continue;
+ }
status_t err_flush = sensor->flush(connection.get(), handle);
if (err_flush == NO_ERROR) {
SensorRecord* rec = mActiveSensors.valueFor(handle);
@@ -907,23 +1075,42 @@
return err;
}
-bool SensorService::canAccessSensor(const Sensor& sensor) {
- return (sensor.getRequiredPermission().isEmpty()) ||
- PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission()));
-}
+bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
+ const String16& opPackageName) {
+ const String8& requiredPermission = sensor.getRequiredPermission();
-bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) {
- if (canAccessSensor(sensor)) {
+ if (requiredPermission.length() <= 0) {
return true;
+ }
+
+ bool hasPermission = false;
+
+ // Runtime permissions can't use the cache as they may change.
+ if (sensor.isRequiredPermissionRuntime()) {
+ hasPermission = checkPermission(String16(requiredPermission),
+ IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
} else {
- String8 errorMessage;
- errorMessage.appendFormat(
- "%s a sensor (%s) without holding its required permission: %s",
- operation,
- sensor.getName().string(),
- sensor.getRequiredPermission().string());
+ hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
+ }
+
+ if (!hasPermission) {
+ ALOGE("%s a sensor (%s) without holding its required permission: %s",
+ operation, sensor.getName().string(), sensor.getRequiredPermission().string());
return false;
}
+
+ const int32_t opCode = sensor.getRequiredAppOp();
+ if (opCode >= 0) {
+ AppOpsManager appOps;
+ if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName)
+ != AppOpsManager::MODE_ALLOWED) {
+ ALOGE("%s a sensor (%s) without enabled required app op: %d",
+ operation, sensor.getName().string(), opCode);
+ return false;
+ }
+ }
+
+ return true;
}
void SensorService::checkWakeLockState() {
@@ -969,6 +1156,33 @@
}
}
+bool SensorService::isWhiteListedPackage(const String8& packageName) {
+ return (packageName.contains(mWhiteListedPackage.string()));
+}
+
+int SensorService::getNumEventsForSensorType(int sensor_event_type) {
+ switch (sensor_event_type) {
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+ return 5;
+
+ case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+ case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+ return 6;
+
+ case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+ return 4;
+
+ case SENSOR_TYPE_SIGNIFICANT_MOTION:
+ case SENSOR_TYPE_STEP_DETECTOR:
+ case SENSOR_TYPE_STEP_COUNTER:
+ return 1;
+
+ default:
+ return 3;
+ }
+}
+
// ---------------------------------------------------------------------------
SensorService::SensorRecord::SensorRecord(
const sp<SensorEventConnection>& connection)
@@ -1025,12 +1239,121 @@
return NULL;
}
+void SensorService::SensorRecord::clearAllPendingFlushConnections() {
+ mPendingFlushConnections.clear();
+}
+
+
+// ---------------------------------------------------------------------------
+SensorService::TrimmedSensorEvent::TrimmedSensorEvent(int sensorType) {
+ mTimestamp = -1;
+ const int numData = SensorService::getNumEventsForSensorType(sensorType);
+ if (sensorType == SENSOR_TYPE_STEP_COUNTER) {
+ mStepCounter = 0;
+ } else {
+ mData = new float[numData];
+ for (int i = 0; i < numData; ++i) {
+ mData[i] = -1.0;
+ }
+ }
+ mHour = mMin = mSec = INT32_MIN;
+}
+
+bool SensorService::TrimmedSensorEvent::isSentinel(const TrimmedSensorEvent& event) {
+ return (event.mHour == INT32_MIN && event.mMin == INT32_MIN && event.mSec == INT32_MIN);
+}
+// --------------------------------------------------------------------------
+SensorService::CircularBuffer::CircularBuffer(int sensor_event_type) {
+ mNextInd = 0;
+ mBufSize = CIRCULAR_BUF_SIZE;
+ if (sensor_event_type == SENSOR_TYPE_STEP_COUNTER ||
+ sensor_event_type == SENSOR_TYPE_SIGNIFICANT_MOTION ||
+ sensor_event_type == SENSOR_TYPE_ACCELEROMETER) {
+ mBufSize = CIRCULAR_BUF_SIZE * 5;
+ }
+ mTrimmedSensorEventArr = new TrimmedSensorEvent *[mBufSize];
+ mSensorType = sensor_event_type;
+ for (int i = 0; i < mBufSize; ++i) {
+ mTrimmedSensorEventArr[i] = new TrimmedSensorEvent(mSensorType);
+ }
+}
+
+void SensorService::CircularBuffer::addEvent(const sensors_event_t& sensor_event) {
+ TrimmedSensorEvent *curr_event = mTrimmedSensorEventArr[mNextInd];
+ curr_event->mTimestamp = sensor_event.timestamp;
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ curr_event->mStepCounter = sensor_event.u64.step_counter;
+ } else {
+ memcpy(curr_event->mData, sensor_event.data,
+ sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+ }
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ curr_event->mHour = timeinfo->tm_hour;
+ curr_event->mMin = timeinfo->tm_min;
+ curr_event->mSec = timeinfo->tm_sec;
+ mNextInd = (mNextInd + 1) % mBufSize;
+}
+
+void SensorService::CircularBuffer::printBuffer(String8& result) const {
+ const int numData = SensorService::getNumEventsForSensorType(mSensorType);
+ int i = mNextInd, eventNum = 1;
+ result.appendFormat("last %d events = < ", mBufSize);
+ do {
+ if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[i])) {
+ // Sentinel, ignore.
+ i = (i + 1) % mBufSize;
+ continue;
+ }
+ result.appendFormat("%d) ", eventNum++);
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ result.appendFormat("%" PRIu64 ",", mTrimmedSensorEventArr[i]->mStepCounter);
+ } else {
+ for (int j = 0; j < numData; ++j) {
+ result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]);
+ }
+ }
+ result.appendFormat("%" PRId64 " %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp,
+ mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin,
+ mTrimmedSensorEventArr[i]->mSec);
+ i = (i + 1) % mBufSize;
+ } while (i != mNextInd);
+ result.appendFormat(">\n");
+}
+
+bool SensorService::CircularBuffer::populateLastEvent(sensors_event_t *event) {
+ int lastEventInd = (mNextInd - 1 + mBufSize) % mBufSize;
+ // Check if the buffer is empty.
+ if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[lastEventInd])) {
+ return false;
+ }
+ event->version = sizeof(sensors_event_t);
+ event->type = mSensorType;
+ event->timestamp = mTrimmedSensorEventArr[lastEventInd]->mTimestamp;
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ event->u64.step_counter = mTrimmedSensorEventArr[lastEventInd]->mStepCounter;
+ } else {
+ memcpy(event->data, mTrimmedSensorEventArr[lastEventInd]->mData,
+ sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+ }
+ return true;
+}
+
+SensorService::CircularBuffer::~CircularBuffer() {
+ for (int i = 0; i < mBufSize; ++i) {
+ delete mTrimmedSensorEventArr[i];
+ }
+ delete [] mTrimmedSensorEventArr;
+}
+
// ---------------------------------------------------------------------------
SensorService::SensorEventConnection::SensorEventConnection(
- const sp<SensorService>& service, uid_t uid)
+ const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
+ const String16& opPackageName)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
- mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0) {
+ mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
+ mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -1062,8 +1385,10 @@
void SensorService::SensorEventConnection::dump(String8& result) {
Mutex::Autolock _l(mConnectionLock);
- result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n",
- mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize);
+ result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL");
+ result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
+ "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
+ mMaxCacheSize);
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n",
@@ -1087,7 +1412,8 @@
bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
Mutex::Autolock _l(mConnectionLock);
- if (!verifyCanAccessSensor(mService->getSensorFromHandle(handle), "Tried adding")) {
+ if (!canAccessSensor(mService->getSensorFromHandle(handle),
+ "Tried adding", mOpPackageName)) {
return false;
}
if (mSensorInfo.indexOfKey(handle) < 0) {
@@ -1126,6 +1452,10 @@
return false;
}
+String8 SensorService::SensorEventConnection::getPackageName() const {
+ return mPackageName;
+}
+
void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle,
bool value) {
Mutex::Autolock _l(mConnectionLock);
@@ -1143,7 +1473,8 @@
void SensorService::SensorEventConnection::updateLooperRegistrationLocked(
const sp<Looper>& looper) {
- bool isConnectionActive = mSensorInfo.size() > 0;
+ bool isConnectionActive = (mSensorInfo.size() > 0 && !mDataInjectionMode) ||
+ mDataInjectionMode;
// If all sensors are unregistered OR Looper has encountered an error, we
// can remove the Fd from the Looper if it has been previously added.
if (!isConnectionActive || mDead) {
@@ -1157,6 +1488,7 @@
int looper_flags = 0;
if (mCacheSize > 0) looper_flags |= ALOOPER_EVENT_OUTPUT;
+ if (mDataInjectionMode) looper_flags |= ALOOPER_EVENT_INPUT;
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const int handle = mSensorInfo.keyAt(i);
if (mService->getSensorFromHandle(handle).isWakeUpSensor()) {
@@ -1200,7 +1532,7 @@
sensors_event_t* scratch,
SensorEventConnection const * const * mapFlushEventsToConnections) {
// filter out events not for this connection
- size_t count = 0;
+ int count = 0;
Mutex::Autolock _l(mConnectionLock);
if (scratch) {
size_t i=0;
@@ -1492,7 +1824,7 @@
status_t err;
if (enabled) {
err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
- reservedFlags);
+ reservedFlags, mOpPackageName);
} else {
err = mService->disable(this, handle);
@@ -1503,11 +1835,11 @@
status_t SensorService::SensorEventConnection::setEventRate(
int handle, nsecs_t samplingPeriodNs)
{
- return mService->setEventRate(this, handle, samplingPeriodNs);
+ return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
}
status_t SensorService::SensorEventConnection::flush() {
- return mService->flushSensor(this);
+ return mService->flushSensor(this, mOpPackageName);
}
int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* /*data*/) {
@@ -1523,26 +1855,55 @@
updateLooperRegistrationLocked(mService->getLooper());
}
mService->checkWakeLockState();
+ if (mDataInjectionMode) {
+ // If the Looper has encountered some error in data injection mode, reset SensorService
+ // back to normal mode.
+ mService->resetToNormalMode();
+ mDataInjectionMode = false;
+ }
return 1;
}
if (events & ALOOPER_EVENT_INPUT) {
- uint32_t numAcks = 0;
- ssize_t ret = ::recv(fd, &numAcks, sizeof(numAcks), MSG_DONTWAIT);
+ unsigned char buf[sizeof(sensors_event_t)];
+ ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
{
Mutex::Autolock _l(mConnectionLock);
- // Sanity check to ensure there are no read errors in recv, numAcks is always
- // within the range and not zero. If any of the above don't hold reset mWakeLockRefCount
- // to zero.
- if (ret != sizeof(numAcks) || numAcks > mWakeLockRefCount || numAcks == 0) {
- ALOGE("Looper read error ret=%d numAcks=%d", ret, numAcks);
- mWakeLockRefCount = 0;
- } else {
- mWakeLockRefCount -= numAcks;
- }
+ if (numBytesRead == sizeof(sensors_event_t)) {
+ if (!mDataInjectionMode) {
+ ALOGE("Data injected in normal mode, dropping event"
+ "package=%s uid=%d", mPackageName.string(), mUid);
+ // Unregister call backs.
+ return 0;
+ }
+ SensorDevice& dev(SensorDevice::getInstance());
+ sensors_event_t sensor_event;
+ memset(&sensor_event, 0, sizeof(sensor_event));
+ memcpy(&sensor_event, buf, sizeof(sensors_event_t));
+ Sensor sensor = mService->getSensorFromHandle(sensor_event.sensor);
+ sensor_event.type = sensor.getType();
+ dev.injectSensorData(&sensor_event);
#if DEBUG_CONNECTIONS
- mTotalAcksReceived += numAcks;
+ ++mEventsReceived;
#endif
+ } else if (numBytesRead == sizeof(uint32_t)) {
+ uint32_t numAcks = 0;
+ memcpy(&numAcks, buf, numBytesRead);
+ // Sanity check to ensure there are no read errors in recv, numAcks is always
+ // within the range and not zero. If any of the above don't hold reset
+ // mWakeLockRefCount to zero.
+ if (numAcks > 0 && numAcks < mWakeLockRefCount) {
+ mWakeLockRefCount -= numAcks;
+ } else {
+ mWakeLockRefCount = 0;
+ }
+#if DEBUG_CONNECTIONS
+ mTotalAcksReceived += numAcks;
+#endif
+ } else {
+ // Read error, reset wakelock refcount.
+ mWakeLockRefCount = 0;
+ }
}
// Check if wakelock can be released by sensorservice. mConnectionLock needs to be released
// here as checkWakeLockState() will need it.
@@ -1561,8 +1922,8 @@
}
int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const {
- int fifoWakeUpSensors = 0;
- int fifoNonWakeUpSensors = 0;
+ size_t fifoWakeUpSensors = 0;
+ size_t fifoNonWakeUpSensors = 0;
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i));
if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index e9ca3a5..9a573ae 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -27,6 +27,7 @@
#include <utils/AndroidThreads.h>
#include <utils/RefBase.h>
#include <utils/Looper.h>
+#include <utils/String8.h>
#include <binder/BinderService.h>
@@ -52,6 +53,9 @@
// For older HALs which don't support batching, use a smaller socket buffer size.
#define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
+#define CIRCULAR_BUF_SIZE 10
+#define SENSOR_REGISTRATIONS_BUF_SIZE 20
+
struct sensors_poll_device_t;
struct sensors_module_t;
@@ -65,6 +69,51 @@
{
friend class BinderService<SensorService>;
+ enum Mode {
+ // The regular operating mode where any application can register/unregister/call flush on
+ // sensors.
+ NORMAL = 0,
+ // This mode is only used for testing purposes. Not all HALs support this mode. In this
+ // mode, the HAL ignores the sensor data provided by physical sensors and accepts the data
+ // that is injected from the SensorService as if it were the real sensor data. This mode
+ // is primarily used for testing various algorithms like vendor provided SensorFusion,
+ // Step Counter and Step Detector etc. Typically in this mode, there will be a client
+ // (a SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps
+ // can unregister and register for any sensor that supports injection. Registering to sensors
+ // that do not support injection will give an error.
+ // TODO(aakella) : Allow exactly one client to inject sensor data at a time.
+ DATA_INJECTION = 1,
+ // This mode is used only for testing sensors. Each sensor can be tested in isolation with
+ // the required sampling_rate and maxReportLatency parameters without having to think about
+ // the data rates requested by other applications. End user devices are always expected to be
+ // in NORMAL mode. When this mode is first activated, all active sensors from all connections
+ // are disabled. Calling flush() will return an error. In this mode, only the requests from
+ // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only
+ // these apps can register/unregister/call flush() on sensors. If SensorService switches to
+ // NORMAL mode again, all sensors that were previously registered to are activated with the
+ // corresponding paramaters if the application hasn't unregistered for sensors in the mean
+ // time.
+ // NOTE: Non whitelisted app whose sensors were previously deactivated may still receive
+ // events if a whitelisted app requests data from the same sensor.
+ RESTRICTED = 2
+
+ // State Transitions supported.
+ // RESTRICTED <--- NORMAL ---> DATA_INJECTION
+ // ---> <---
+
+ // Shell commands to switch modes in SensorService.
+ // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in
+ // restricted mode it is treated as a NO_OP (and packageName is NOT changed).
+ // $ adb shell dumpsys sensorservice restrict .cts.
+ //
+ // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in
+ // data_injection mode it is treated as a NO_OP (and packageName is NOT changed).
+ // $ adb shell dumpsys sensorservice data_injection .xts.
+ //
+ // 3) Reset sensorservice back to NORMAL mode.
+ // $ adb shell dumpsys sensorservice enable
+ };
+
static const char* WAKE_LOCK_NAME;
static char const* getServiceName() ANDROID_API { return "sensorservice"; }
@@ -77,8 +126,10 @@
virtual bool threadLoop();
// ISensorServer interface
- virtual Vector<Sensor> getSensorList();
- virtual sp<ISensorEventConnection> createSensorEventConnection();
+ virtual Vector<Sensor> getSensorList(const String16& opPackageName);
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+ int requestedMode, const String16& opPackageName);
+ virtual int isDataInjectionEnabled();
virtual status_t dump(int fd, const Vector<String16>& args);
class SensorEventConnection : public BnSensorEventConnection, public LooperCallback {
@@ -133,7 +184,6 @@
// connection FD may be added to the Looper. The flags to set are determined by the internal
// state of the connection. FDs are added to the looper when wake-up sensors are registered
// (to poll for acknowledgements) and when write fails on the socket when there are too many
- // events (to poll when the FD is available for writing). FDs are removed when there is an
// error and the other end hangs up or when this client unregisters for this connection.
void updateLooperRegistration(const sp<Looper>& looper);
void updateLooperRegistrationLocked(const sp<Looper>& looper);
@@ -156,6 +206,8 @@
// mWakeLockRefCount is reset to zero. needsWakeLock method will always return false, if
// this flag is set.
bool mDead;
+
+ bool mDataInjectionMode;
struct FlushInfo {
// The number of flush complete events dropped for this sensor is stored here.
// They are sent separately before the next batch of events.
@@ -169,14 +221,16 @@
KeyedVector<int, FlushInfo> mSensorInfo;
sensors_event_t *mEventCache;
int mCacheSize, mMaxCacheSize;
-
+ String8 mPackageName;
+ const String16 mOpPackageName;
#if DEBUG_CONNECTIONS
int mEventsReceived, mEventsSent, mEventsSentFromCache;
int mTotalAcksNeeded, mTotalAcksReceived;
#endif
public:
- SensorEventConnection(const sp<SensorService>& service, uid_t uid);
+ SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
+ bool isDataInjectionMode, const String16& opPackageName);
status_t sendEvents(sensors_event_t const* buffer, size_t count,
sensors_event_t* scratch,
@@ -190,6 +244,7 @@
void dump(String8& result);
bool needsWakeLock();
void resetWakeLockRefCount();
+ String8 getPackageName() const;
uid_t getUid() const { return mUid; }
};
@@ -208,6 +263,7 @@
void addPendingFlushConnection(const sp<SensorEventConnection>& connection);
void removeFirstPendingFlushConnection();
SensorEventConnection * getFirstPendingFlushConnection();
+ void clearAllPendingFlushConnections();
};
class SensorEventAckReceiver : public Thread {
@@ -217,6 +273,63 @@
SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {}
};
+ // sensor_event_t with only the data and the timestamp.
+ struct TrimmedSensorEvent {
+ union {
+ float *mData;
+ uint64_t mStepCounter;
+ };
+ // Timestamp from the sensor_event.
+ int64_t mTimestamp;
+ // HH:MM:SS local time at which this sensor event is read at SensorService. Useful
+ // for debugging.
+ int32_t mHour, mMin, mSec;
+
+ TrimmedSensorEvent(int sensorType);
+ static bool isSentinel(const TrimmedSensorEvent& event);
+
+ ~TrimmedSensorEvent() {
+ delete [] mData;
+ }
+ };
+
+ // A circular buffer of TrimmedSensorEvents. The size of this buffer is typically 10. The
+ // last N events generated from the sensor are stored in this buffer. The buffer is NOT
+ // cleared when the sensor unregisters and as a result one may see very old data in the
+ // dumpsys output but this is WAI.
+ class CircularBuffer {
+ int mNextInd;
+ int mSensorType;
+ int mBufSize;
+ TrimmedSensorEvent ** mTrimmedSensorEventArr;
+ public:
+ CircularBuffer(int sensor_event_type);
+ void addEvent(const sensors_event_t& sensor_event);
+ void printBuffer(String8& buffer) const;
+ bool populateLastEvent(sensors_event_t *event);
+ ~CircularBuffer();
+ };
+
+ struct SensorRegistrationInfo {
+ int32_t mSensorHandle;
+ String8 mPackageName;
+ bool mActivated;
+ int32_t mSamplingRateUs;
+ int32_t mMaxReportLatencyUs;
+ int32_t mHour, mMin, mSec;
+
+ SensorRegistrationInfo() : mPackageName() {
+ mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
+ mHour = mMin = mSec = INT32_MIN;
+ mActivated = false;
+ }
+
+ static bool isSentinel(const SensorRegistrationInfo& info) {
+ return (info.mHour == INT32_MIN && info.mMin == INT32_MIN && info.mSec == INT32_MIN);
+ }
+ };
+
+ static int getNumEventsForSensorType(int sensor_event_type);
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
Sensor getSensorFromHandle(int handle) const;
@@ -231,8 +344,8 @@
const sp<SensorEventConnection>& connection, int handle);
void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count);
- static bool canAccessSensor(const Sensor& sensor);
- static bool verifyCanAccessSensor(const Sensor& sensor, const char* operation);
+ static bool canAccessSensor(const Sensor& sensor, const char* operation,
+ const String16& opPackageName);
// SensorService acquires a partial wakelock for delivering events from wake up sensors. This
// method checks whether all the events from these wake up sensors have been delivered to the
// corresponding applications, if yes the wakelock is released.
@@ -261,6 +374,15 @@
// to the output vector.
void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections);
+ // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
+ // allowed to register for or call flush on sensors. Typically only cts test packages are
+ // allowed.
+ bool isWhiteListedPackage(const String8& packageName);
+
+ // Reset the state of SensorService to NORMAL mode.
+ status_t resetToNormalMode();
+ status_t resetToNormalModeLocked();
+
// constants
Vector<Sensor> mSensorList;
Vector<Sensor> mUserSensorListDebug;
@@ -282,17 +404,28 @@
bool mWakeLockAcquired;
sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
SensorEventConnection const **mMapFlushEventsToConnections;
+ Mode mCurrentOperatingMode;
+ // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
+ // applications with this packageName are allowed to activate/deactivate or call flush on
+ // sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to
+ // sensors.
+ String8 mWhiteListedPackage;
// The size of this vector is constant, only the items are mutable
- KeyedVector<int32_t, sensors_event_t> mLastEventSeen;
+ KeyedVector<int32_t, CircularBuffer *> mLastEventSeen;
+ int mNextSensorRegIndex;
+ Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
public:
void cleanupConnection(SensorEventConnection* connection);
status_t enable(const sp<SensorEventConnection>& connection, int handle,
- nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags);
+ nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
+ const String16& opPackageName);
status_t disable(const sp<SensorEventConnection>& connection, int handle);
- status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
- status_t flushSensor(const sp<SensorEventConnection>& connection);
+ status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns,
+ const String16& opPackageName);
+ status_t flushSensor(const sp<SensorEventConnection>& connection,
+ const String16& opPackageName);
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index 1025fa8..cfdf6a3 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <android/sensor.h>
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
@@ -25,7 +26,7 @@
static nsecs_t sStartTime = 0;
-int receiver(int fd, int events, void* data)
+int receiver(__unused int fd, __unused int events, void* data)
{
sp<SensorEventQueue> q((SensorEventQueue*)data);
ssize_t n;
@@ -44,7 +45,7 @@
oldTimeStamp = buffer[i].timestamp;
if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
- printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+ printf("%" PRId64 "\t%8f\t%8f\t%8f\t%f\n",
buffer[i].timestamp,
buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
1.0/t);
@@ -59,9 +60,9 @@
}
-int main(int argc, char** argv)
+int main()
{
- SensorManager& mgr(SensorManager::getInstance());
+ SensorManager mgr(String16("Sensor Service Test"));
Sensor const* const* list;
ssize_t count = mgr.getSensorList(&list);
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index 24f30ff..a142bad 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -37,7 +37,7 @@
class vec;
template <typename TYPE, size_t SIZE>
-class vbase;
+struct vbase;
namespace helpers {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e2a0167..5ff79a9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -76,7 +76,6 @@
mFiltering(false),
mNeedsFiltering(false),
mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
- mSecure(false),
mProtectedByApp(false),
mHasSurface(false),
mClientRef(client),
@@ -96,6 +95,8 @@
layerFlags |= layer_state_t::eLayerHidden;
if (flags & ISurfaceComposerClient::eOpaque)
layerFlags |= layer_state_t::eLayerOpaque;
+ if (flags & ISurfaceComposerClient::eSecure)
+ layerFlags |= layer_state_t::eLayerSecure;
if (flags & ISurfaceComposerClient::eNonPremultiplied)
mPremultipliedAlpha = false;
@@ -256,7 +257,6 @@
mFormat = format;
mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
- mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false;
mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
mCurrentOpacity = getOpacityForFormat(format);
@@ -551,14 +551,7 @@
const Transform& tr = hw->getTransform();
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
-
- // Pass full-surface damage down untouched
- if (surfaceDamageRegion.isRect() &&
- surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) {
- layer.setSurfaceDamage(surfaceDamageRegion);
- } else {
- layer.setSurfaceDamage(tr.transform(surfaceDamageRegion));
- }
+ layer.setSurfaceDamage(surfaceDamageRegion);
if (mSidebandStream.get()) {
layer.setSidebandStream(mSidebandStream);
@@ -858,6 +851,12 @@
return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
}
+bool Layer::isSecure() const
+{
+ const Layer::State& s(mDrawingState);
+ return (s.flags & layer_state_t::eLayerSecure);
+}
+
bool Layer::isProtected() const
{
const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
@@ -1102,11 +1101,26 @@
// ----------------------------------------------------------------------------
bool Layer::shouldPresentNow(const DispSync& dispSync) const {
+ if (mSidebandStreamChanged) {
+ return true;
+ }
+
Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems.empty()) {
+ return false;
+ }
+ auto timestamp = mQueueItems[0].mTimestamp;
nsecs_t expectedPresent =
mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
- return mQueueItems.empty() ?
- false : mQueueItems[0].mTimestamp < expectedPresent;
+
+ // Ignore timestamps more than a second in the future
+ bool isPlausible = timestamp < (expectedPresent + s2ns(1));
+ ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible "
+ "relative to expectedPresent %" PRId64, mName.string(), timestamp,
+ expectedPresent);
+
+ bool isDue = timestamp < expectedPresent;
+ return isDue || !isPlausible;
}
bool Layer::onPreComposition() {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4e222b7..c1e5e9f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -174,7 +174,7 @@
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
- virtual bool isSecure() const { return mSecure; }
+ virtual bool isSecure() const;
/*
* isProtected - true if the layer may contain protected content in the
@@ -402,7 +402,6 @@
mutable Texture mTexture;
// page-flip thread (currently main thread)
- bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
// protected by mLock
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bf9b886..de0f921 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -149,7 +149,11 @@
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
- mHasColorMatrix(false)
+ mHasColorMatrix(false),
+ mHasPoweredOff(false),
+ mFrameBuckets(),
+ mTotalTime(0),
+ mLastSwapTime(0)
{
ALOGI("SurfaceFlinger is starting");
@@ -438,15 +442,6 @@
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(mEGLDisplay, NULL, NULL);
- // start the EventThread
- sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc);
- sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc);
- mEventQueue.setEventThread(mSFEventThread);
-
// Initialize the H/W composer object. There may or may not be an
// actual hardware composer underneath.
mHwc = new HWComposer(this,
@@ -498,6 +493,15 @@
// (which may happens before we render something)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
+ // start the EventThread
+ sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ vsyncPhaseOffsetNs, true, "app");
+ mEventThread = new EventThread(vsyncSrc);
+ sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ sfVsyncPhaseOffsetNs, true, "sf");
+ mSFEventThread = new EventThread(sfVsyncSrc);
+ mEventQueue.setEventThread(mSFEventThread);
+
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
@@ -997,8 +1001,8 @@
}
}
+ const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (kIgnorePresentFences) {
- const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (hw->isDisplayOn()) {
enableHardwareVsync();
}
@@ -1017,6 +1021,26 @@
}
mAnimFrameTracker.advanceFrame();
}
+
+ if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ return;
+ }
+
+ nsecs_t currentTime = systemTime();
+ if (mHasPoweredOff) {
+ mHasPoweredOff = false;
+ } else {
+ nsecs_t period = mPrimaryDispSync.getPeriod();
+ nsecs_t elapsedTime = currentTime - mLastSwapTime;
+ size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+ if (numPeriods < NUM_BUCKETS - 1) {
+ mFrameBuckets[numPeriods] += elapsedTime;
+ } else {
+ mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+ }
+ mTotalTime += elapsedTime;
+ }
+ mLastSwapTime = currentTime;
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -2211,9 +2235,7 @@
if (layer->setTransparentRegionHint(s.transparentRegion))
flags |= eTraversalNeeded;
}
- if ((what & layer_state_t::eVisibilityChanged) ||
- (what & layer_state_t::eOpacityChanged)) {
- // TODO: should we just use an eFlagsChanged for this?
+ if (what & layer_state_t::eFlagsChanged) {
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
@@ -2411,6 +2433,7 @@
}
mVisibleRegionsDirty = true;
+ mHasPoweredOff = true;
repaintEverything();
} else if (mode == HWC_POWER_MODE_OFF) {
if (type == DisplayDevice::DISPLAY_PRIMARY) {
@@ -2511,6 +2534,13 @@
mPrimaryDispSync.dump(result);
dumpAll = false;
}
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--static-screen"))) {
+ index++;
+ dumpStaticScreenStats(result);
+ dumpAll = false;
+ }
}
if (dumpAll) {
@@ -2614,6 +2644,23 @@
result.append(config);
}
+void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
+{
+ result.appendFormat("Static screen stats:\n");
+ for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
+ float bucketTimeSec = mFrameBuckets[b] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+ result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n",
+ b + 1, bucketTimeSec, percent);
+ }
+ float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+ result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n",
+ NUM_BUCKETS - 1, bucketTimeSec, percent);
+}
+
void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
String8& result) const
{
@@ -2660,6 +2707,11 @@
mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
result.append("\n");
+ // Dump static screen stats
+ result.append("\n");
+ dumpStaticScreenStats(result);
+ result.append("\n");
+
/*
* Dump the visible layer list
*/
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 74f9031..3759a92 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -418,6 +418,8 @@
void logFrameStats();
+ void dumpStaticScreenStats(String8& result) const;
+
/* ------------------------------------------------------------------------
* Attributes
*/
@@ -496,6 +498,13 @@
mat4 mColorMatrix;
bool mHasColorMatrix;
+
+ // Static screen stats
+ bool mHasPoweredOff;
+ static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
+ nsecs_t mFrameBuckets[NUM_BUCKETS];
+ nsecs_t mTotalTime;
+ nsecs_t mLastSwapTime;
};
}; // namespace android