recovery: ui: Support hardware virtual keys
* Also swipe left -> KEY_BACK
Change-Id: I6bd8054485d680df35abb86cb79f1dda683e4459
diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_sdcard_install.cpp
index 1aa8768..e528e48 100644
--- a/install/fuse_sdcard_install.cpp
+++ b/install/fuse_sdcard_install.cpp
@@ -97,13 +97,16 @@
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
return "";
}
-
- const std::string& item = entries[chosen_item];
- if (chosen_item == 0) {
- // Go up but continue browsing (if the caller is BrowseDirectory).
+ if (chosen_item == Device::kGoHome) {
+ return "@";
+ }
+ if (chosen_item == Device::kGoBack || chosen_item == 0) {
+ // Go up but continue browsing (if the caller is browse_directory).
return "";
}
+ const std::string& item = entries[chosen_item];
+
std::string new_path = path + "/" + item;
if (new_path.back() == '/') {
// Recurse down into a subdirectory.
@@ -140,6 +143,9 @@
}
std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
+ if (path == "@") {
+ return INSTALL_NONE;
+ }
if (path.empty()) {
LOG(ERROR) << "\n-- No package file selected.\n";
ensure_path_unmounted(SDCARD_ROOT);
diff --git a/minui/events.cpp b/minui/events.cpp
index 0eb8f72..c0f64f1 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -237,7 +237,8 @@
}
}
-void ev_iterate_touch_inputs(const std::function<void(int)>& key_detected) {
+void ev_iterate_touch_inputs(const std::function<void(int)>& touch_device_detected,
+ const std::function<void(int)>& key_detected) {
for (size_t i = 0; i < g_ev_dev_count; ++i) {
// Use unsigned long to match ioctl's parameter type.
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)] = {}; // NOLINT
@@ -253,6 +254,8 @@
continue;
}
+ touch_device_detected(ev_fdinfo[i].fd);
+
for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
if (test_bit(key_code, key_bits)) {
key_detected(key_code);
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index 5c7302c..a6b7b20 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -156,7 +156,8 @@
void ev_exit();
int ev_add_fd(android::base::unique_fd&& fd, ev_callback cb);
void ev_iterate_available_keys(const std::function<void(int)>& key_detected);
-void ev_iterate_touch_inputs(const std::function<void(int)>& key_detected);
+void ev_iterate_touch_inputs(const std::function<void(int)>& touch_device_detected,
+ const std::function<void(int)>& key_detected);
int ev_sync_key_state(const ev_set_key_callback& set_key_cb);
// 'timeout' has the same semantics as poll(2).
diff --git a/recovery.cpp b/recovery.cpp
index 5fc673e..9cf81e8 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -424,8 +424,10 @@
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
break;
}
- if (entries[chosen_item] == "Back") break;
-
+ if (chosen_item == Device::kGoHome || chosen_item == Device::kGoBack ||
+ chosen_item == entries.size() - 1) {
+ break;
+ }
ui->ShowFile(entries[chosen_item]);
}
}
@@ -498,6 +500,11 @@
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
return Device::KEY_INTERRUPTED;
}
+ // We are already in the main menu
+ if (chosen_item == Device::kGoBack || chosen_item == Device::kGoHome) {
+ continue;
+ }
+
// Device-specific code may take some action here. It may return one of the core actions
// handled in the switch statement below.
Device::BuiltinAction chosen_action =
diff --git a/recovery_ui/device.cpp b/recovery_ui/device.cpp
index e7ae1a3..cee07a4 100644
--- a/recovery_ui/device.cpp
+++ b/recovery_ui/device.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -77,18 +78,31 @@
}
switch (key) {
+ case KEY_RIGHTSHIFT:
case KEY_DOWN:
case KEY_VOLUMEDOWN:
+ case KEY_MENU:
return kHighlightDown;
case KEY_UP:
case KEY_VOLUMEUP:
+ case KEY_SEARCH:
return kHighlightUp;
case KEY_ENTER:
case KEY_POWER:
+ case BTN_MOUSE:
+ case KEY_SEND:
return kInvokeItem;
+ case KEY_HOME:
+ case KEY_HOMEPAGE:
+ return kGoHome;
+
+ case KEY_BACKSPACE:
+ case KEY_BACK:
+ return kGoBack;
+
default:
// If you have all of the above buttons, any other buttons
// are ignored. Otherwise, any button cycles the highlight.
diff --git a/recovery_ui/include/recovery_ui/device.h b/recovery_ui/include/recovery_ui/device.h
index 7c76cdb..7efa075 100644
--- a/recovery_ui/include/recovery_ui/device.h
+++ b/recovery_ui/include/recovery_ui/device.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +33,8 @@
static constexpr const int kHighlightUp = -2;
static constexpr const int kHighlightDown = -3;
static constexpr const int kInvokeItem = -4;
+ static constexpr const int kGoBack = -5;
+ static constexpr const int kGoHome = -6;
// ENTER vs REBOOT: The latter will trigger a reboot that goes through bootloader, which allows
// using a new bootloader / recovery image if applicable. For example, REBOOT_RESCUE goes from
diff --git a/recovery_ui/include/recovery_ui/ui.h b/recovery_ui/include/recovery_ui/ui.h
index c2c012b..a28e15d 100644
--- a/recovery_ui/include/recovery_ui/ui.h
+++ b/recovery_ui/include/recovery_ui/ui.h
@@ -264,6 +264,7 @@
const int touch_low_threshold_;
const int touch_high_threshold_;
+ void OnTouchDeviceDetected(int fd);
void OnKeyDetected(int key_code);
void OnTouchEvent();
int OnInputEvent(int fd, uint32_t epevents);
@@ -294,12 +295,19 @@
bool has_down_key;
bool has_touch_screen;
+ struct vkey_t {
+ int keycode;
+ Point min_;
+ Point max_;
+ };
+
// Touch event related variables. See the comments in RecoveryUI::OnInputEvent().
int touch_slot_;
Point touch_pos_;
Point touch_start_;
bool touch_finger_down_;
bool touch_swiping_;
+ std::vector<vkey_t> virtual_keys_;
bool is_bootreason_recovery_ui_;
std::thread input_thread_;
diff --git a/recovery_ui/screen_ui.cpp b/recovery_ui/screen_ui.cpp
index 870db62..17b0890 100644
--- a/recovery_ui/screen_ui.cpp
+++ b/recovery_ui/screen_ui.cpp
@@ -1232,10 +1232,19 @@
break;
case Device::kNoAction:
break;
+ case Device::kGoBack:
+ chosen_item = Device::kGoBack;
+ break;
+ case Device::kGoHome:
+ chosen_item = Device::kGoHome;
+ break;
}
} else if (!menu_only) {
chosen_item = action;
}
+ if (chosen_item == Device::kGoBack || chosen_item == Device::kGoHome) {
+ break;
+ }
}
menu_.reset();
diff --git a/recovery_ui/ui.cpp b/recovery_ui/ui.cpp
index 6e239ef..aed6f49 100644
--- a/recovery_ui/ui.cpp
+++ b/recovery_ui/ui.cpp
@@ -89,6 +89,48 @@
}
}
+void RecoveryUI::OnTouchDeviceDetected(int fd) {
+ char name[256];
+ char path[PATH_MAX];
+ char buf[4096];
+
+ memset(name, 0, sizeof(name));
+ if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
+ return;
+ }
+ sprintf(path, "/sys/board_properties/virtualkeys.%s", name);
+ int vkfd = open(path, O_RDONLY);
+ if (vkfd < 0) {
+ LOG(INFO) << "vkeys: could not open " << path;
+ return;
+ }
+ ssize_t len = read(vkfd, buf, sizeof(buf));
+ close(vkfd);
+ if (len <= 0) {
+ LOG(ERROR) << "vkeys: could not read " << path;
+ return;
+ }
+ buf[len] = '\0';
+
+ char* p = buf;
+ char* endp;
+ for (size_t n = 0; p < buf + len && *p == '0'; ++n) {
+ int val[6];
+ int f;
+ for (f = 0; *p && f < 6; ++f) {
+ val[f] = strtol(p, &endp, 0);
+ if (p == endp) break;
+ p = endp + 1;
+ }
+ if (f != 6 || val[0] != 0x01) break;
+ vkey_t vk;
+ vk.keycode = val[1];
+ vk.min_ = Point(val[2] - val[4] / 2, val[3] - val[5] / 2);
+ vk.max_ = Point(val[2] + val[4] / 2, val[3] + val[5] / 2);
+ virtual_keys_.push_back(vk);
+ }
+}
+
void RecoveryUI::OnKeyDetected(int key_code) {
if (key_code == KEY_POWER) {
has_power_key = true;
@@ -147,7 +189,9 @@
ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));
if (touch_screen_allowed_) {
- ev_iterate_touch_inputs(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));
+ ev_iterate_touch_inputs(
+ std::bind(&RecoveryUI::OnTouchDeviceDetected, this, std::placeholders::_1),
+ std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));
// Parse /proc/cmdline to determine if it's booting into recovery with a bootreason of
// "recovery_ui". This specific reason is set by some (wear) bootloaders, to allow an easier way
@@ -191,6 +235,14 @@
} else if (abs(delta.x()) < touch_low_threshold_ && abs(delta.y()) > touch_high_threshold_) {
direction = delta.y() < 0 ? SwipeDirection::UP : SwipeDirection::DOWN;
} else {
+ for (const auto& vk : virtual_keys_) {
+ if (touch_start_.x() >= vk.min_.x() && touch_start_.x() < vk.max_.x() &&
+ touch_start_.y() >= vk.min_.y() && touch_start_.y() < vk.max_.y()) {
+ ProcessKey(vk.keycode, 1); // press key
+ ProcessKey(vk.keycode, 0); // and release it
+ return;
+ }
+ }
LOG(DEBUG) << "Ignored " << delta.x() << " " << delta.y() << " (low: " << touch_low_threshold_
<< ", high: " << touch_high_threshold_ << ")";
return;
@@ -215,6 +267,9 @@
break;
case SwipeDirection::LEFT:
+ ProcessKey(KEY_BACK, 1); // press back key
+ ProcessKey(KEY_BACK, 0); // and release it
+ break;
case SwipeDirection::RIGHT:
ProcessKey(KEY_POWER, 1); // press power key
ProcessKey(KEY_POWER, 0); // and release it