recovery: touch UI
[aleasto] make scrolling natural
[DD3Boh] Adapt to Android 11
Change-Id: Ibf64aa70e21d88f9d0b2c60fc1b66a9995837464
diff --git a/recovery_ui/device.cpp b/recovery_ui/device.cpp
index 3a42216..51125a8 100644
--- a/recovery_ui/device.cpp
+++ b/recovery_ui/device.cpp
@@ -92,6 +92,11 @@
case KEY_SEARCH:
return kHighlightUp;
+ case KEY_SCROLLUP:
+ return kScrollUp;
+ case KEY_SCROLLDOWN:
+ return kScrollDown;
+
case KEY_ENTER:
case KEY_POWER:
case BTN_MOUSE:
diff --git a/recovery_ui/include/recovery_ui/device.h b/recovery_ui/include/recovery_ui/device.h
index d6e94fc..67c4da0 100644
--- a/recovery_ui/include/recovery_ui/device.h
+++ b/recovery_ui/include/recovery_ui/device.h
@@ -39,6 +39,8 @@
static constexpr const int kGoBack = -5;
static constexpr const int kGoHome = -6;
static constexpr const int kDoSideload = -7;
+ static constexpr const int kScrollUp = -8;
+ static constexpr const int kScrollDown = -9;
// 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/screen_ui.h b/recovery_ui/include/recovery_ui/screen_ui.h
index 55a2f89..cedeb79 100644
--- a/recovery_ui/include/recovery_ui/screen_ui.h
+++ b/recovery_ui/include/recovery_ui/screen_ui.h
@@ -96,10 +96,16 @@
// Sets the current selection to |sel|. Handle the overflow cases depending on if the menu is
// scrollable.
virtual int Select(int sel) = 0;
+ // Select by index within the currently visible items.
+ // Matches Select() if not scrollable
+ virtual int SelectVisible(int relative_sel) = 0;
+ // Scroll the menu by updown, if scrollable
+ virtual int Scroll(int updown) = 0;
// Displays the menu headers on the screen at offset x, y
virtual int DrawHeader(int x, int y) const = 0;
// Iterates over the menu items and displays each of them at offset x, y.
virtual int DrawItems(int x, int y, int screen_width, bool long_press) const = 0;
+ virtual size_t ItemsCount() const = 0;
virtual bool IsMain() const = 0;
protected:
@@ -120,8 +126,11 @@
size_t initial_selection, int char_height, const DrawInterface& draw_funcs);
int Select(int sel) override;
+ int SelectVisible(int relative_sel) override;
+ int Scroll(int updown) override;
int DrawHeader(int x, int y) const override;
int DrawItems(int x, int y, int screen_width, bool long_press) const override;
+ size_t ItemsCount() const override;
bool IsMain() const override {
// Main menus have no headers
@@ -132,9 +141,6 @@
return wrappable_;
}
- // Returns count of menu items.
- size_t ItemsCount() const;
-
// Returns the index of the first menu item.
size_t MenuStart() const;
@@ -186,8 +192,15 @@
size_t initial_selection, const DrawInterface& draw_funcs);
int Select(int sel) override;
+ int SelectVisible(int sel) override {
+ return Select(sel);
+ }
+ int Scroll(int updown __unused) override {
+ return selection_;
+ };
int DrawHeader(int x, int y) const override;
int DrawItems(int x, int y, int screen_width, bool long_press) const override;
+ size_t ItemsCount() const override;
bool IsMain() const override {
return true;
}
@@ -310,6 +323,10 @@
// For Lid switch handle
int SetSwCallback(int code, int value) override;
+ int MenuItemHeight() const override {
+ return MenuCharHeight() + 2 * MenuItemPadding();
+ }
+
protected:
static constexpr int kMenuIndent = 24;
@@ -353,6 +370,8 @@
// Sets the menu highlight to the given index, wrapping if necessary. Returns the actual item
// selected.
virtual int SelectMenu(int sel);
+ virtual int SelectMenu(const Point& point);
+ virtual int ScrollMenu(int updown);
// Returns the help message displayed on top of the menu.
virtual std::vector<std::string> GetMenuHelpMessage() const;
@@ -409,9 +428,6 @@
int MenuItemPadding() const override {
return menu_char_height_ * 2 / 3;
}
- int MenuItemHeight() const override {
- return MenuCharHeight() + 2 * MenuItemPadding();
- }
std::unique_ptr<MenuDrawFunctions> menu_draw_funcs_;
@@ -471,6 +487,7 @@
std::vector<std::string> title_lines_;
std::unique_ptr<Menu> menu_;
+ int menu_start_y_;
// An alternate text screen, swapped with 'text_' when we're viewing a log file.
char** file_viewer_text_;
diff --git a/recovery_ui/include/recovery_ui/ui.h b/recovery_ui/include/recovery_ui/ui.h
index 3013c99..ff9ffc5 100644
--- a/recovery_ui/include/recovery_ui/ui.h
+++ b/recovery_ui/include/recovery_ui/ui.h
@@ -104,6 +104,42 @@
INTERRUPTED = -2,
};
+ enum EventType {
+ EXTRA,
+ KEY,
+ TOUCH,
+ };
+
+ class InputEvent {
+ public:
+ InputEvent() : type_(EventType::EXTRA), evt_({ 0 }) {
+ evt_.key = static_cast<int>(KeyError::TIMED_OUT);
+ }
+ explicit InputEvent(EventType type, KeyError key)
+ : type_(type), evt_({ static_cast<int>(key) }) {}
+ explicit InputEvent(int key) : type_(EventType::KEY), evt_({ key }) {}
+ explicit InputEvent(const Point& pos) : type_(EventType::TOUCH), evt_({ 0 }) {
+ evt_.pos = pos;
+ }
+
+ EventType type() const {
+ return type_;
+ }
+ int key() const {
+ return evt_.key;
+ }
+ const Point& pos() const {
+ return evt_.pos;
+ }
+
+ private:
+ EventType type_;
+ union {
+ int key;
+ Point pos;
+ } evt_;
+ };
+
RecoveryUI();
virtual ~RecoveryUI();
@@ -154,7 +190,7 @@
// Waits for a key and return it. May return TIMED_OUT after timeout and
// KeyError::INTERRUPTED on a key interrupt.
- virtual int WaitKey();
+ virtual InputEvent WaitInputEvent();
virtual void CancelWaitKey();
// Wakes up the UI if it is waiting on key input, causing WaitKey to return KeyError::INTERRUPTED.
@@ -228,6 +264,10 @@
return false;
}
+ virtual int MenuItemHeight() const {
+ return 1;
+ }
+
// Set whether or not the fastbootd logo is displayed.
void SetEnableFastbootdLogo(bool enable) {
fastbootd_logo_enabled_ = enable;
@@ -247,6 +287,7 @@
protected:
void EnqueueKey(int key_code);
+ void EnqueueTouch(const Point& pos);
// The normal and dimmed brightness percentages (default: 50 and 25, which means 50% and 25% of
// the max_brightness). Because the absolute values may vary across devices. These two values can
@@ -275,7 +316,9 @@
void OnTouchDeviceDetected(int fd);
void OnKeyDetected(int key_code);
- void OnTouchEvent();
+ void OnTouchPress();
+ void OnTouchTrack();
+ void OnTouchRelease();
int OnInputEvent(int fd, uint32_t epevents);
void ProcessKey(int key_code, int updown);
void TimeKey(int key_code, int count);
@@ -286,10 +329,11 @@
virtual int SetSwCallback(int code, int value) = 0;
// Key event input queue
- std::mutex key_queue_mutex;
- std::condition_variable key_queue_cond;
+ std::mutex event_queue_mutex;
+ std::condition_variable event_queue_cond;
bool key_interrupted_;
- int key_queue[256], key_queue_len;
+ InputEvent event_queue[256];
+ int event_queue_len;
// key press events
std::mutex key_press_mutex;
@@ -308,6 +352,10 @@
bool has_touch_screen;
struct vkey_t {
+ bool inside(const Point& p) const {
+ return (p.x() >= min_.x() && p.x() < max_.x() && p.y() >= min_.y() && p.y() < max_.y());
+ }
+
int keycode;
Point min_;
Point max_;
@@ -315,10 +363,13 @@
// Touch event related variables. See the comments in RecoveryUI::OnInputEvent().
int touch_slot_;
+ bool touch_finger_down_;
+ bool touch_saw_x_;
+ bool touch_saw_y_;
+ bool touch_reported_;
Point touch_pos_;
Point touch_start_;
- bool touch_finger_down_;
- bool touch_swiping_;
+ Point touch_track_;
std::vector<vkey_t> virtual_keys_;
bool is_bootreason_recovery_ui_;
diff --git a/recovery_ui/screen_ui.cpp b/recovery_ui/screen_ui.cpp
index 82d51f9..f636a5b 100644
--- a/recovery_ui/screen_ui.cpp
+++ b/recovery_ui/screen_ui.cpp
@@ -145,6 +145,32 @@
return selection_;
}
+int TextMenu::SelectVisible(int relative_sel) {
+ int sel = relative_sel;
+ if (menu_start_ > 0) {
+ sel += menu_start_;
+ }
+
+ return Select(sel);
+}
+
+int TextMenu::Scroll(int updown) {
+ if ((updown > 0 && menu_start_ + max_display_items_ < ItemsCount()) ||
+ (updown < 0 && menu_start_ > 0)) {
+ menu_start_ += updown;
+
+ /* We can receive a kInvokeItem event from a different source than touch,
+ like from Power button. For this reason, selection should not get out of
+ the screen. Constrain it to the first or last visible item of the list */
+ if (selection_ < menu_start_) {
+ selection_ = menu_start_;
+ } else if (selection_ >= menu_start_ + max_display_items_) {
+ selection_ = menu_start_ + max_display_items_ - 1;
+ }
+ }
+ return selection_;
+}
+
int TextMenu::DrawHeader(int x, int y) const {
int offset = 0;
@@ -254,6 +280,10 @@
return offset;
}
+size_t GraphicMenu::ItemsCount() const {
+ return graphic_items_.size();
+}
+
bool GraphicMenu::Validate(size_t max_width, size_t max_height, const GRSurface* graphic_headers,
const std::vector<const GRSurface*>& graphic_items) {
int offset = 0;
@@ -627,16 +657,20 @@
FlushKeys();
while (true) {
- int key = WaitKey();
- if (key == static_cast<int>(KeyError::INTERRUPTED)) break;
- if (key == KEY_POWER || key == KEY_ENTER) {
- break;
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
- selected = (selected == 0) ? locales_entries.size() - 1 : selected - 1;
- SelectAndShowBackgroundText(locales_entries, selected);
- } else if (key == KEY_DOWN || key == KEY_VOLUMEDOWN) {
- selected = (selected == locales_entries.size() - 1) ? 0 : selected + 1;
- SelectAndShowBackgroundText(locales_entries, selected);
+ InputEvent evt = WaitInputEvent();
+ if (evt.type() == EventType::EXTRA) {
+ if (evt.key() == static_cast<int>(KeyError::INTERRUPTED)) break;
+ }
+ if (evt.type() == EventType::KEY) {
+ if (evt.key() == KEY_POWER || evt.key() == KEY_ENTER) {
+ break;
+ } else if (evt.key() == KEY_UP || evt.key() == KEY_VOLUMEUP) {
+ selected = (selected == 0) ? locales_entries.size() - 1 : selected - 1;
+ SelectAndShowBackgroundText(locales_entries, selected);
+ } else if (evt.key() == KEY_DOWN || evt.key() == KEY_VOLUMEDOWN) {
+ selected = (selected == locales_entries.size() - 1) ? 0 : selected + 1;
+ SelectAndShowBackgroundText(locales_entries, selected);
+ }
}
}
@@ -797,6 +831,7 @@
}
y += menu_->DrawHeader(x, y);
+ menu_start_y_ = y + 12; // Skip horizontal rule and some margin
y += menu_->DrawItems(x, y, ScreenWidth(), IsLongPress());
}
@@ -1201,11 +1236,20 @@
Redraw();
while (show_prompt) {
show_prompt = false;
- int key = WaitKey();
- if (key == static_cast<int>(KeyError::INTERRUPTED)) return;
- if (key == KEY_POWER || key == KEY_ENTER) {
+ InputEvent evt = WaitInputEvent();
+ if (evt.type() == EventType::EXTRA) {
+ if (evt.key() == static_cast<int>(KeyError::INTERRUPTED)) {
+ return;
+ }
+ }
+ if (evt.type() != EventType::KEY) {
+ show_prompt = true;
+ continue;
+ }
+ if (evt.key() == KEY_POWER || evt.key() == KEY_ENTER || evt.key() == KEY_BACKSPACE ||
+ evt.key() == KEY_BACK || evt.key() == KEY_HOME || evt.key() == KEY_HOMEPAGE) {
return;
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
+ } else if (evt.key() == KEY_UP || evt.key() == KEY_VOLUMEUP || evt.key() == KEY_SCROLLUP) {
if (offsets.size() <= 1) {
show_prompt = true;
} else {
@@ -1302,6 +1346,49 @@
return sel;
}
+int ScreenRecoveryUI::SelectMenu(const Point& point) {
+ int new_sel = Device::kNoAction;
+ std::lock_guard<std::mutex> lg(updateMutex);
+ if (menu_) {
+ if (!menu_->IsMain()) {
+ // Back arrow hitbox
+ const static int logo_width = gr_get_width(lineage_logo_.get());
+ const static int logo_height = gr_get_height(lineage_logo_.get());
+ const static int icon_w = gr_get_width(back_icon_.get());
+ const static int icon_h = gr_get_height(back_icon_.get());
+ const static int centered_x = ScreenWidth() / 2 - logo_width / 2;
+ const static int icon_x = centered_x / 2 - icon_w / 2;
+ const static int icon_y = margin_height_ + logo_height / 2 - icon_h / 2;
+
+ if (point.x() >= icon_x && point.x() <= icon_x + icon_w &&
+ point.y() >= icon_y && point.y() <= icon_y + icon_h) {
+ return Device::kGoBack;
+ }
+ }
+
+ if (point.y() >= menu_start_y_ &&
+ point.y() < menu_start_y_ + menu_->ItemsCount() * MenuItemHeight()) {
+ int old_sel = menu_->selection();
+ int relative_sel = (point.y() - menu_start_y_) / MenuItemHeight();
+ new_sel = menu_->SelectVisible(relative_sel);
+ if (new_sel != -1 && new_sel != old_sel) {
+ update_screen_locked();
+ }
+ }
+ }
+ return new_sel;
+}
+
+int ScreenRecoveryUI::ScrollMenu(int updown) {
+ std::lock_guard<std::mutex> lg(updateMutex);
+ int sel = Device::kNoAction;
+ if (menu_) {
+ sel = menu_->Scroll(updown);
+ update_screen_locked();
+ }
+ return sel;
+}
+
size_t ScreenRecoveryUI::ShowMenu(std::unique_ptr<Menu>&& menu, bool menu_only,
const std::function<int(int, bool)>& key_handler) {
// Throw away keys pressed previously, so user doesn't accidentally trigger menu items.
@@ -1320,23 +1407,37 @@
int selected = menu_->selection();
int chosen_item = -1;
while (chosen_item < 0) {
- int key = WaitKey();
- if (key == static_cast<int>(KeyError::INTERRUPTED)) { // WaitKey() was interrupted.
- return static_cast<size_t>(KeyError::INTERRUPTED);
- }
- if (key == static_cast<int>(KeyError::TIMED_OUT)) { // WaitKey() timed out.
- if (WasTextEverVisible()) {
- continue;
- } else {
- LOG(INFO) << "Timed out waiting for key input; rebooting.";
- menu_.reset();
- Redraw();
- return static_cast<size_t>(KeyError::TIMED_OUT);
+ InputEvent evt = WaitInputEvent();
+ if (evt.type() == EventType::EXTRA) {
+ if (evt.key() == static_cast<int>(KeyError::INTERRUPTED)) {
+ // WaitKey() was interrupted.
+ return static_cast<size_t>(KeyError::INTERRUPTED);
+ }
+ if (evt.key() == static_cast<int>(KeyError::TIMED_OUT)) { // WaitKey() timed out.
+ if (WasTextEverVisible()) {
+ continue;
+ } else {
+ LOG(INFO) << "Timed out waiting for key input; rebooting.";
+ menu_.reset();
+ Redraw();
+ return static_cast<size_t>(KeyError::TIMED_OUT);
+ }
}
}
- bool visible = IsTextVisible();
- int action = key_handler(key, visible);
+ int action = Device::kNoAction;
+ if (evt.type() == EventType::TOUCH) {
+ int touch_sel = SelectMenu(evt.pos());
+ if (touch_sel < 0) {
+ action = touch_sel;
+ } else {
+ action = Device::kInvokeItem;
+ selected = touch_sel;
+ }
+ } else {
+ bool visible = IsTextVisible();
+ action = key_handler(evt.key(), visible);
+ }
if (action < 0) {
switch (action) {
case Device::kHighlightUp:
@@ -1345,6 +1446,12 @@
case Device::kHighlightDown:
selected = SelectMenu(++selected);
break;
+ case Device::kScrollUp:
+ selected = ScrollMenu(-1);
+ break;
+ case Device::kScrollDown:
+ selected = ScrollMenu(1);
+ break;
case Device::kInvokeItem:
if (selected < 0) {
chosen_item = Device::kGoBack;
diff --git a/recovery_ui/stub_ui.cpp b/recovery_ui/stub_ui.cpp
index a56b3f7..87605cf 100644
--- a/recovery_ui/stub_ui.cpp
+++ b/recovery_ui/stub_ui.cpp
@@ -25,11 +25,12 @@
size_t /* initial_selection */, bool /* menu_only */,
const std::function<int(int, bool)>& /*key_handler*/) {
while (true) {
- int key = WaitKey();
// Exit the loop in the case of interruption or time out.
- if (key == static_cast<int>(KeyError::INTERRUPTED) ||
- key == static_cast<int>(KeyError::TIMED_OUT)) {
- return static_cast<size_t>(key);
+ InputEvent evt = WaitInputEvent();
+ if (evt.type() == EventType::EXTRA) {
+ if (evt.key() == static_cast<int>(KeyError::INTERRUPTED) ||
+ evt.key() == static_cast<int>(KeyError::TIMED_OUT))
+ return static_cast<size_t>(evt.key());
}
}
LOG(FATAL) << "Unreachable key selected in ShowMenu of stub UI";
diff --git a/recovery_ui/ui.cpp b/recovery_ui/ui.cpp
index edb3cdf..41f8526 100644
--- a/recovery_ui/ui.cpp
+++ b/recovery_ui/ui.cpp
@@ -74,7 +74,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),
@@ -85,6 +85,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));
@@ -256,62 +260,48 @@
}
}
-void RecoveryUI::OnTouchDetected(int dx, int dy) {
- SwipeDirection 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;
}
- // Flip swipe direction if screen is rotated upside down
- if (gr_get_rotation() == GRRotation::DOWN) {
- direction = FlipSwipeDirection(direction);
+ // 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;
}
- 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;
+ // If we tracked a vertical swipe, ignore the release
+ if (touch_track_ != touch_start_) {
+ return;
+ }
- case SwipeDirection::DOWN:
- ProcessKey(KEY_DOWN, 1); // press down key
- ProcessKey(KEY_DOWN, 0); // and release it
- 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
- break;
- };
+ // Simple touch
+ EnqueueTouch(touch_pos_);
}
int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
@@ -322,10 +312,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
//
@@ -342,14 +328,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;
@@ -385,13 +374,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:
@@ -496,11 +495,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();
}
}
@@ -539,23 +549,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) {
@@ -568,8 +578,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);
}
}
@@ -577,14 +587,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() {
@@ -593,10 +603,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() {
@@ -640,8 +650,8 @@
}
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) {