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