am 5d1630a9: Merge "Fix ScreenRecoveryUI to handle devices without power/up/down."
* commit '5d1630a926a02ca13a66eb1e385eabba16b04cfc':
Fix ScreenRecoveryUI to handle devices without power/up/down.
diff --git a/minui/events.cpp b/minui/events.cpp
index 2c41eb8..daa10c6 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -201,7 +201,7 @@
return 0;
}
-void ev_iterate_available_keys(ev_key_callback cb, void* data) {
+void ev_iterate_available_keys(std::function<void(int)> f) {
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
@@ -224,7 +224,7 @@
for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
if (test_bit(key_code, key_bits)) {
- cb(key_code, data);
+ f(key_code);
}
}
}
diff --git a/minui/minui.h b/minui/minui.h
index 8f2ff11..82abb8a 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -68,13 +68,11 @@
typedef int (*ev_callback)(int fd, uint32_t epevents, void* data);
typedef int (*ev_set_key_callback)(int code, int value, void* data);
-typedef void (*ev_key_callback)(int code, void* data);
int ev_init(ev_callback input_cb, void* data);
void ev_exit(void);
int ev_add_fd(int fd, ev_callback cb, void* data);
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data);
-void ev_iterate_available_keys(ev_key_callback cb, void* data);
// 'timeout' has the same semantics as poll(2).
// 0 : don't block
@@ -130,4 +128,11 @@
}
#endif
+#ifdef __cplusplus
+
+#include <functional>
+void ev_iterate_available_keys(std::function<void(int)> f);
+
+#endif
+
#endif
diff --git a/recovery.cpp b/recovery.cpp
index cdbb598..43a42ea 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -545,12 +545,10 @@
if (action < 0) {
switch (action) {
case Device::kHighlightUp:
- --selected;
- selected = ui->SelectMenu(selected);
+ selected = ui->SelectMenu(--selected);
break;
case Device::kHighlightDown:
- ++selected;
- selected = ui->SelectMenu(selected);
+ selected = ui->SelectMenu(++selected);
break;
case Device::kInvokeItem:
chosen_item = selected;
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 6d8df68..b62417f 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -185,6 +185,9 @@
case MENU_SEL_BG:
gr_color(0, 106, 157, 255);
break;
+ case MENU_SEL_BG_ACTIVE:
+ gr_color(0, 156, 100, 255);
+ break;
case MENU_SEL_FG:
gr_color(255, 255, 255, 255);
break;
@@ -220,7 +223,7 @@
if (i == menu_top + menu_sel) {
// draw the highlight bar
- SetColor(MENU_SEL_BG);
+ SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG);
gr_fill(0, y-2, gr_fb_width(), y+char_height+2);
// white text of selected item
SetColor(MENU_SEL_FG);
@@ -638,3 +641,9 @@
update_screen_locked();
pthread_mutex_unlock(&updateMutex);
}
+
+void ScreenRecoveryUI::KeyLongPress(int) {
+ // Redraw so that if we're in the menu, the highlight
+ // will change color to indicate a successful long press.
+ Redraw();
+}
diff --git a/screen_ui.h b/screen_ui.h
index 41ff4af..ea1a95b 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -56,10 +56,12 @@
int SelectMenu(int sel);
void EndMenu();
+ void KeyLongPress(int);
+
void Redraw();
- enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL };
- virtual void SetColor(UIElement e);
+ enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_BG_ACTIVE, MENU_SEL_FG, LOG, TEXT_FILL };
+ void SetColor(UIElement e);
private:
Icon currentIcon;
diff --git a/ui.cpp b/ui.cpp
index 8716245..064890e 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -51,26 +51,40 @@
key_down_count(0),
enable_reboot(true),
consecutive_power_keys(0),
- last_key(-1) {
+ last_key(-1),
+ has_power_key(false),
+ has_up_key(false),
+ has_down_key(false) {
pthread_mutex_init(&key_queue_mutex, NULL);
pthread_cond_init(&key_queue_cond, NULL);
self = this;
memset(key_pressed, 0, sizeof(key_pressed));
}
+void RecoveryUI::OnKeyDetected(int key_code) {
+ if (key_code == KEY_POWER) {
+ has_power_key = true;
+ } else if (key_code == KEY_DOWN || key_code == KEY_VOLUMEDOWN) {
+ has_down_key = true;
+ } else if (key_code == KEY_UP || key_code == KEY_VOLUMEUP) {
+ has_up_key = true;
+ }
+}
+
void RecoveryUI::Init() {
ev_init(input_callback, NULL);
+
+ using namespace std::placeholders;
+ ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, _1));
+
pthread_create(&input_t, NULL, input_thread, NULL);
}
-
int RecoveryUI::input_callback(int fd, uint32_t epevents, void* data) {
struct input_event ev;
- int ret;
-
- ret = ev_get_input(fd, epevents, &ev);
- if (ret)
+ if (ev_get_input(fd, epevents, &ev) == -1) {
return -1;
+ }
if (ev.type == EV_SYN) {
return 0;
@@ -95,8 +109,9 @@
self->rel_sum = 0;
}
- if (ev.type == EV_KEY && ev.code <= KEY_MAX)
+ if (ev.type == EV_KEY && ev.code <= KEY_MAX) {
self->process_key(ev.code, ev.value);
+ }
return 0;
}
@@ -142,8 +157,7 @@
pthread_mutex_unlock(&key_queue_mutex);
if (register_key) {
- NextCheckKeyIsLong(long_press);
- switch (CheckKey(key_code)) {
+ switch (CheckKey(key_code, long_press)) {
case RecoveryUI::IGNORE:
break;
@@ -257,23 +271,44 @@
return pressed;
}
+bool RecoveryUI::IsLongPress() {
+ pthread_mutex_lock(&key_queue_mutex);
+ bool result = key_long_press;
+ pthread_mutex_unlock(&key_queue_mutex);
+ return result;
+}
+
void RecoveryUI::FlushKeys() {
pthread_mutex_lock(&key_queue_mutex);
key_queue_len = 0;
pthread_mutex_unlock(&key_queue_mutex);
}
-// The default CheckKey implementation assumes the device has power,
-// volume up, and volume down keys.
-//
-// - Hold power and press vol-up to toggle display.
-// - Press power seven times in a row to reboot.
-// - Alternate vol-up and vol-down seven times to mount /system.
-RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) {
- if ((IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) || key == KEY_HOME) {
- return TOGGLE;
+RecoveryUI::KeyAction RecoveryUI::CheckKey(int key, bool is_long_press) {
+ pthread_mutex_lock(&key_queue_mutex);
+ key_long_press = false;
+ pthread_mutex_unlock(&key_queue_mutex);
+
+ // If we have power and volume up keys, that chord is the signal to toggle the text display.
+ if (has_power_key && has_up_key) {
+ if (key == KEY_VOLUMEUP && IsKeyPressed(KEY_POWER)) {
+ return TOGGLE;
+ }
+ } else {
+ // Otherwise long press of any button toggles to the text display,
+ // and there's no way to toggle back (but that's pretty useless anyway).
+ if (is_long_press && !IsTextVisible()) {
+ return TOGGLE;
+ }
+
+ // Also, for button-limited devices, a long press is translated to KEY_ENTER.
+ if (is_long_press && IsTextVisible()) {
+ EnqueueKey(KEY_ENTER);
+ return IGNORE;
+ }
}
+ // Press power seven times in a row to reboot.
if (key == KEY_POWER) {
pthread_mutex_lock(&key_queue_mutex);
bool reboot_enabled = enable_reboot;
@@ -290,14 +325,10 @@
}
last_key = key;
-
- return ENQUEUE;
+ return IsTextVisible() ? ENQUEUE : IGNORE;
}
-void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) {
-}
-
-void RecoveryUI::KeyLongPress(int key) {
+void RecoveryUI::KeyLongPress(int) {
}
void RecoveryUI::SetEnableReboot(bool enabled) {
diff --git a/ui.h b/ui.h
index bc728b0..0d5ab55 100644
--- a/ui.h
+++ b/ui.h
@@ -69,30 +69,27 @@
// --- key handling ---
- // Wait for keypress and return it. May return -1 after timeout.
+ // Wait for a key and return it. May return -1 after timeout.
virtual int WaitKey();
virtual bool IsKeyPressed(int key);
+ virtual bool IsLongPress();
// Erase any queued-up keys.
virtual void FlushKeys();
- // Called on each keypress, even while operations are in progress.
+ // Called on each key press, even while operations are in progress.
// Return value indicates whether an immediate operation should be
// triggered (toggling the display, rebooting the device), or if
// the key should be enqueued for use by the main thread.
enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE };
- virtual KeyAction CheckKey(int key);
-
- // Called immediately before each call to CheckKey(), tell you if
- // the key was long-pressed.
- virtual void NextCheckKeyIsLong(bool is_long_press);
+ virtual KeyAction CheckKey(int key, bool is_long_press);
// Called when a key is held down long enough to have been a
// long-press (but before the key is released). This means that
// if the key is eventually registered (released without any other
- // keys being pressed in the meantime), NextCheckKeyIsLong() will
- // be called with "true".
+ // keys being pressed in the meantime), CheckKey will be called with
+ // 'is_long_press' true.
virtual void KeyLongPress(int key);
// Normally in recovery there's a key sequence that triggers
@@ -110,8 +107,8 @@
virtual void StartMenu(const char* const * headers, const char* const * items,
int initial_selection) = 0;
- // Set the menu highlight to the given index, and return it (capped to
- // the range [0..numitems).
+ // Set the menu highlight to the given index, wrapping if necessary.
+ // Returns the actual item selected.
virtual int SelectMenu(int sel) = 0;
// End menu mode, resetting the text overlay so that ui_print()
@@ -136,14 +133,20 @@
int consecutive_power_keys;
int last_key;
- typedef struct {
+ bool has_power_key;
+ bool has_up_key;
+ bool has_down_key;
+
+ struct key_timer_t {
RecoveryUI* ui;
int key_code;
int count;
- } key_timer_t;
+ };
pthread_t input_t;
+ void OnKeyDetected(int key_code);
+
static void* input_thread(void* cookie);
static int input_callback(int fd, uint32_t epevents, void* data);
void process_key(int key_code, int updown);