recovery: touch UI
[aleasto] make scrolling natural
Change-Id: Ibf64aa70e21d88f9d0b2c60fc1b66a9995837464
diff --git a/recovery_ui/ui.cpp b/recovery_ui/ui.cpp
index ef02fea..45d747b 100644
--- a/recovery_ui/ui.cpp
+++ b/recovery_ui/ui.cpp
@@ -64,7 +64,7 @@
touch_high_threshold_(android::base::GetIntProperty("ro.recovery.ui.touch_high_threshold",
kDefaultTouchHighThreshold)),
key_interrupted_(false),
- key_queue_len(0),
+ event_queue_len(0),
key_last_down(-1),
key_long_press(false),
key_down_count(0),
@@ -76,6 +76,10 @@
has_down_key(false),
has_touch_screen(false),
touch_slot_(0),
+ touch_finger_down_(false),
+ touch_saw_x_(false),
+ touch_saw_y_(false),
+ touch_reported_(false),
is_bootreason_recovery_ui_(false),
screensaver_state_(ScreensaverState::DISABLED) {
memset(key_pressed, 0, sizeof(key_pressed));
@@ -223,58 +227,57 @@
return true;
}
-void RecoveryUI::OnTouchEvent() {
- Point delta = touch_pos_ - touch_start_;
- enum SwipeDirection { UP, DOWN, RIGHT, LEFT } direction;
+void RecoveryUI::OnTouchPress() {
+ touch_start_ = touch_track_ = touch_pos_;
+}
- // We only consider a valid swipe if:
- // - the delta along one axis is below touch_low_threshold_;
- // - and the delta along the other axis is beyond touch_high_threshold_.
- if (abs(delta.y()) < touch_low_threshold_ && abs(delta.x()) > touch_high_threshold_) {
- direction = delta.x() < 0 ? SwipeDirection::LEFT : SwipeDirection::RIGHT;
- } 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;
- }
+void RecoveryUI::OnTouchTrack() {
+ if (touch_pos_.y() <= gr_fb_height()) {
+ while (abs(touch_pos_.y() - touch_track_.y()) >= MenuItemHeight()) {
+ int dy = touch_pos_.y() - touch_track_.y();
+ int key = (dy < 0) ? KEY_SCROLLDOWN : KEY_SCROLLUP;
+ ProcessKey(key, 1); // press key
+ ProcessKey(key, 0); // and release it
+ int sgn = (dy > 0) - (dy < 0);
+ touch_track_.y(touch_track_.y() + sgn * MenuItemHeight());
}
- LOG(DEBUG) << "Ignored " << delta.x() << " " << delta.y() << " (low: " << touch_low_threshold_
- << ", high: " << touch_high_threshold_ << ")";
- return;
}
+}
+void RecoveryUI::OnTouchRelease() {
// Allow turning on text mode with any swipe, if bootloader has set a bootreason of recovery_ui.
if (is_bootreason_recovery_ui_ && !IsTextVisible()) {
ShowText(true);
return;
}
- LOG(DEBUG) << "Swipe direction=" << direction;
- switch (direction) {
- case SwipeDirection::UP:
- ProcessKey(KEY_UP, 1); // press up key
- ProcessKey(KEY_UP, 0); // and release it
- break;
+ // Check vkeys. Only report if touch both starts and ends in the vkey.
+ if (touch_start_.y() > gr_fb_height() && touch_pos_.y() > gr_fb_height()) {
+ for (const auto& vk : virtual_keys_) {
+ if (vk.inside(touch_start_) && vk.inside(touch_pos_)) {
+ ProcessKey(vk.keycode, 1); // press key
+ ProcessKey(vk.keycode, 0); // and release it
+ }
+ }
+ return;
+ }
- case SwipeDirection::DOWN:
- ProcessKey(KEY_DOWN, 1); // press down key
- ProcessKey(KEY_DOWN, 0); // and release it
- break;
+ // If we tracked a vertical swipe, ignore the release
+ if (touch_track_ != touch_start_) {
+ return;
+ }
- 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
- break;
- };
+ // Check for horizontal swipe
+ Point delta = touch_pos_ - touch_start_;
+ if (abs(delta.y()) < touch_low_threshold_ && abs(delta.x()) > touch_high_threshold_) {
+ int key = (delta.x() < 0) ? KEY_BACK : KEY_POWER;
+ ProcessKey(key, 1); // press key
+ ProcessKey(key, 0); // and release it
+ return;
+ }
+
+ // Simple touch
+ EnqueueTouch(touch_pos_);
}
int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
@@ -285,10 +288,6 @@
// Touch inputs handling.
//
- // We handle the touch inputs by tracking the position changes between initial contacting and
- // upon lifting. touch_start_X/Y record the initial positions, with touch_finger_down set. Upon
- // detecting the lift, we unset touch_finger_down and detect a swipe based on position changes.
- //
// Per the doc Multi-touch Protocol at below, there are two protocols.
// https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
//
@@ -305,14 +304,17 @@
if (ev.type == EV_SYN) {
if (touch_screen_allowed_ && ev.code == SYN_REPORT) {
- // There might be multiple SYN_REPORT events. We should only detect a swipe after lifting the
- // contact.
- if (touch_finger_down_ && !touch_swiping_) {
- touch_start_ = touch_pos_;
- touch_swiping_ = true;
- } else if (!touch_finger_down_ && touch_swiping_) {
- touch_swiping_ = false;
- OnTouchEvent();
+ // There might be multiple SYN_REPORT events. Only report press/release once.
+ if (!touch_reported_ && touch_finger_down_) {
+ if (touch_saw_x_ && touch_saw_y_) {
+ OnTouchPress();
+ touch_reported_ = true;
+ touch_saw_x_ = touch_saw_y_ = false;
+ }
+ } else if (touch_reported_ && !touch_finger_down_) {
+ OnTouchRelease();
+ touch_reported_ = false;
+ touch_saw_x_ = touch_saw_y_ = false;
}
}
return 0;
@@ -348,13 +350,23 @@
switch (ev.code) {
case ABS_MT_POSITION_X:
- touch_pos_.x(ev.value);
touch_finger_down_ = true;
+ touch_saw_x_ = true;
+ touch_pos_.x(ev.value);
+ if (touch_reported_ && touch_saw_y_) {
+ OnTouchTrack();
+ touch_saw_x_ = touch_saw_y_ = false;
+ }
break;
case ABS_MT_POSITION_Y:
- touch_pos_.y(ev.value);
touch_finger_down_ = true;
+ touch_saw_y_ = true;
+ touch_pos_.y(ev.value);
+ if (touch_reported_ && touch_saw_x_) {
+ OnTouchTrack();
+ touch_saw_x_ = touch_saw_y_ = false;
+ }
break;
case ABS_MT_TRACKING_ID:
@@ -401,7 +413,7 @@
bool long_press = false;
{
- std::lock_guard<std::mutex> lg(key_queue_mutex);
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
key_pressed[key_code] = updown;
if (updown) {
++key_down_count;
@@ -448,7 +460,7 @@
std::this_thread::sleep_for(750ms); // 750 ms == "long"
bool long_press = false;
{
- std::lock_guard<std::mutex> lg(key_queue_mutex);
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
if (key_last_down == key_code && key_down_count == count) {
long_press = key_long_press = true;
}
@@ -457,11 +469,22 @@
}
void RecoveryUI::EnqueueKey(int key_code) {
- std::lock_guard<std::mutex> lg(key_queue_mutex);
- const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
- if (key_queue_len < queue_max) {
- key_queue[key_queue_len++] = key_code;
- key_queue_cond.notify_one();
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
+ const int queue_max = sizeof(event_queue) / sizeof(event_queue[0]);
+ if (event_queue_len < queue_max) {
+ InputEvent event(key_code);
+ event_queue[event_queue_len++] = event;
+ event_queue_cond.notify_one();
+ }
+}
+
+void RecoveryUI::EnqueueTouch(const Point& pos) {
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
+ const int queue_max = sizeof(event_queue) / sizeof(event_queue[0]);
+ if (event_queue_len < queue_max) {
+ InputEvent event(pos);
+ event_queue[event_queue_len++] = event;
+ event_queue_cond.notify_one();
}
}
@@ -500,23 +523,23 @@
}
}
-int RecoveryUI::WaitKey() {
- std::unique_lock<std::mutex> lk(key_queue_mutex);
+RecoveryUI::InputEvent RecoveryUI::WaitInputEvent() {
+ std::unique_lock<std::mutex> lk(event_queue_mutex);
// Check for a saved key queue interruption.
if (key_interrupted_) {
SetScreensaverState(ScreensaverState::NORMAL);
- return static_cast<int>(KeyError::INTERRUPTED);
+ return InputEvent(EventType::EXTRA, KeyError::INTERRUPTED);
}
// Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is plugged in.
do {
- bool rc = key_queue_cond.wait_for(lk, std::chrono::seconds(UI_WAIT_KEY_TIMEOUT_SEC), [this] {
- return this->key_queue_len != 0 || key_interrupted_;
+ bool rc = event_queue_cond.wait_for(lk, std::chrono::seconds(UI_WAIT_KEY_TIMEOUT_SEC), [this] {
+ return this->event_queue_len != 0 || key_interrupted_;
});
if (key_interrupted_) {
SetScreensaverState(ScreensaverState::NORMAL);
- return static_cast<int>(KeyError::INTERRUPTED);
+ return InputEvent(EventType::EXTRA, KeyError::INTERRUPTED);
}
if (screensaver_state_ != ScreensaverState::DISABLED) {
if (!rc) {
@@ -529,8 +552,8 @@
} else if (screensaver_state_ != ScreensaverState::NORMAL) {
// Drop the first key if it's changing from OFF to NORMAL.
if (screensaver_state_ == ScreensaverState::OFF) {
- if (key_queue_len > 0) {
- memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
+ if (event_queue_len > 0) {
+ memcpy(&event_queue[0], &event_queue[1], sizeof(int) * --event_queue_len);
}
}
@@ -538,14 +561,14 @@
SetScreensaverState(ScreensaverState::NORMAL);
}
}
- } while (IsUsbConnected() && key_queue_len == 0);
+ } while (IsUsbConnected() && event_queue_len == 0);
- int key = static_cast<int>(KeyError::TIMED_OUT);
- if (key_queue_len > 0) {
- key = key_queue[0];
- memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
+ InputEvent event;
+ if (event_queue_len > 0) {
+ event = event_queue[0];
+ memcpy(&event_queue[0], &event_queue[1], sizeof(InputEvent) * --event_queue_len);
}
- return key;
+ return event;
}
void RecoveryUI::CancelWaitKey() {
@@ -554,10 +577,10 @@
void RecoveryUI::InterruptKey() {
{
- std::lock_guard<std::mutex> lg(key_queue_mutex);
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
key_interrupted_ = true;
}
- key_queue_cond.notify_one();
+ event_queue_cond.notify_one();
}
bool RecoveryUI::IsUsbConnected() {
@@ -577,13 +600,13 @@
}
bool RecoveryUI::IsKeyPressed(int key) {
- std::lock_guard<std::mutex> lg(key_queue_mutex);
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
int pressed = key_pressed[key];
return pressed;
}
bool RecoveryUI::IsLongPress() {
- std::lock_guard<std::mutex> lg(key_queue_mutex);
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
bool result = key_long_press;
return result;
}
@@ -601,13 +624,13 @@
}
void RecoveryUI::FlushKeys() {
- std::lock_guard<std::mutex> lg(key_queue_mutex);
- key_queue_len = 0;
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
+ event_queue_len = 0;
}
RecoveryUI::KeyAction RecoveryUI::CheckKey(int key, bool is_long_press) {
{
- std::lock_guard<std::mutex> lg(key_queue_mutex);
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
key_long_press = false;
}
@@ -651,6 +674,6 @@
void RecoveryUI::KeyLongPress(int) {}
void RecoveryUI::SetEnableReboot(bool enabled) {
- std::lock_guard<std::mutex> lg(key_queue_mutex);
+ std::lock_guard<std::mutex> lg(event_queue_mutex);
enable_reboot = enabled;
}