recovery: Add ability to interrupt UI
Normally calling a UI method will block indefinitely until the UI is actually used. This creates a method to interrupt the UI, causing waitKey to return -2. This in turn, will cause ShowMenu to return -2. This allows switching between recovery and fastbootd via usb commands. Test: adb shell /data/nativetest64/recovery_unit_test/recovery_unit_test Bug: 78793464 Change-Id: I4c6c9aa18d79070877841a5c9818acf723fa6096
This commit is contained in:
parent
6f1f2c811a
commit
b76af93ab5
6 changed files with 163 additions and 33 deletions
1
device.h
1
device.h
|
@ -47,6 +47,7 @@ class Device {
|
||||||
MOUNT_SYSTEM = 10,
|
MOUNT_SYSTEM = 10,
|
||||||
RUN_GRAPHICS_TEST = 11,
|
RUN_GRAPHICS_TEST = 11,
|
||||||
RUN_LOCALE_TEST = 12,
|
RUN_LOCALE_TEST = 12,
|
||||||
|
KEY_INTERRUPTED = 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Device(RecoveryUI* ui);
|
explicit Device(RecoveryUI* ui);
|
||||||
|
|
31
recovery.cpp
31
recovery.cpp
|
@ -326,6 +326,11 @@ static std::string browse_directory(const std::string& path, Device* device) {
|
||||||
headers, entries, chosen_item, true,
|
headers, entries, chosen_item, true,
|
||||||
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
|
||||||
|
// Return if WaitKey() was interrupted.
|
||||||
|
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& item = entries[chosen_item];
|
const std::string& item = entries[chosen_item];
|
||||||
if (chosen_item == 0) {
|
if (chosen_item == 0) {
|
||||||
// Go up but continue browsing (if the caller is browse_directory).
|
// Go up but continue browsing (if the caller is browse_directory).
|
||||||
|
@ -401,6 +406,11 @@ static bool prompt_and_wipe_data(Device* device) {
|
||||||
size_t chosen_item = ui->ShowMenu(
|
size_t chosen_item = ui->ShowMenu(
|
||||||
headers, items, 0, true,
|
headers, items, 0, true,
|
||||||
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
|
||||||
|
// If ShowMenu() returned RecoveryUI::KeyError::INTERRUPTED, WaitKey() was interrupted.
|
||||||
|
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (chosen_item != 1) {
|
if (chosen_item != 1) {
|
||||||
return true; // Just reboot, no wipe; not a failure, user asked for it
|
return true; // Just reboot, no wipe; not a failure, user asked for it
|
||||||
}
|
}
|
||||||
|
@ -597,6 +607,11 @@ static void choose_recovery_file(Device* device) {
|
||||||
chosen_item = ui->ShowMenu(
|
chosen_item = ui->ShowMenu(
|
||||||
headers, entries, chosen_item, true,
|
headers, entries, chosen_item, true,
|
||||||
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
|
||||||
|
// Handle WaitKey() interrupt.
|
||||||
|
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (entries[chosen_item] == "Back") break;
|
if (entries[chosen_item] == "Back") break;
|
||||||
|
|
||||||
ui->ShowFile(entries[chosen_item]);
|
ui->ShowFile(entries[chosen_item]);
|
||||||
|
@ -745,12 +760,16 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
|
||||||
size_t chosen_item = ui->ShowMenu(
|
size_t chosen_item = ui->ShowMenu(
|
||||||
{}, device->GetMenuItems(), 0, false,
|
{}, device->GetMenuItems(), 0, false,
|
||||||
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
// Handle Interrupt key
|
||||||
|
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
|
||||||
|
return Device::KEY_INTERRUPTED;
|
||||||
|
}
|
||||||
// Device-specific code may take some action here. It may return one of the core actions
|
// Device-specific code may take some action here. It may return one of the core actions
|
||||||
// handled in the switch statement below.
|
// handled in the switch statement below.
|
||||||
Device::BuiltinAction chosen_action = (chosen_item == static_cast<size_t>(-1))
|
Device::BuiltinAction chosen_action =
|
||||||
? Device::REBOOT
|
(chosen_item == static_cast<size_t>(RecoveryUI::KeyError::TIMED_OUT))
|
||||||
: device->InvokeMenuItem(chosen_item);
|
? Device::REBOOT
|
||||||
|
: device->InvokeMenuItem(chosen_item);
|
||||||
|
|
||||||
bool should_wipe_cache = false;
|
bool should_wipe_cache = false;
|
||||||
switch (chosen_action) {
|
switch (chosen_action) {
|
||||||
|
@ -831,6 +850,9 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Device::KEY_INTERRUPTED:
|
||||||
|
return Device::KEY_INTERRUPTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1072,6 +1094,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||||
title_lines.insert(std::begin(title_lines), "Android Recovery");
|
title_lines.insert(std::begin(title_lines), "Android Recovery");
|
||||||
ui->SetTitle(title_lines);
|
ui->SetTitle(title_lines);
|
||||||
|
|
||||||
|
ui->ResetKeyInterruptStatus();
|
||||||
device->StartRecovery();
|
device->StartRecovery();
|
||||||
|
|
||||||
printf("Command:");
|
printf("Command:");
|
||||||
|
|
|
@ -417,6 +417,7 @@ void ScreenRecoveryUI::CheckBackgroundTextImages() {
|
||||||
FlushKeys();
|
FlushKeys();
|
||||||
while (true) {
|
while (true) {
|
||||||
int key = WaitKey();
|
int key = WaitKey();
|
||||||
|
if (key == static_cast<int>(KeyError::INTERRUPTED)) break;
|
||||||
if (key == KEY_POWER || key == KEY_ENTER) {
|
if (key == KEY_POWER || key == KEY_ENTER) {
|
||||||
break;
|
break;
|
||||||
} else if (key == KEY_UP || key == KEY_VOLUMEUP) {
|
} else if (key == KEY_UP || key == KEY_VOLUMEUP) {
|
||||||
|
@ -925,6 +926,7 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
|
||||||
while (show_prompt) {
|
while (show_prompt) {
|
||||||
show_prompt = false;
|
show_prompt = false;
|
||||||
int key = WaitKey();
|
int key = WaitKey();
|
||||||
|
if (key == static_cast<int>(KeyError::INTERRUPTED)) return;
|
||||||
if (key == KEY_POWER || key == KEY_ENTER) {
|
if (key == KEY_POWER || key == KEY_ENTER) {
|
||||||
return;
|
return;
|
||||||
} else if (key == KEY_UP || key == KEY_VOLUMEUP) {
|
} else if (key == KEY_UP || key == KEY_VOLUMEUP) {
|
||||||
|
@ -1017,19 +1019,26 @@ size_t ScreenRecoveryUI::ShowMenu(const std::vector<std::string>& headers,
|
||||||
// Throw away keys pressed previously, so user doesn't accidentally trigger menu items.
|
// Throw away keys pressed previously, so user doesn't accidentally trigger menu items.
|
||||||
FlushKeys();
|
FlushKeys();
|
||||||
|
|
||||||
|
// If there is a key interrupt in progress, return KeyError::INTERRUPTED without starting the
|
||||||
|
// menu.
|
||||||
|
if (IsKeyInterrupted()) return static_cast<size_t>(KeyError::INTERRUPTED);
|
||||||
|
|
||||||
StartMenu(headers, items, initial_selection);
|
StartMenu(headers, items, initial_selection);
|
||||||
|
|
||||||
int selected = initial_selection;
|
int selected = initial_selection;
|
||||||
int chosen_item = -1;
|
int chosen_item = -1;
|
||||||
while (chosen_item < 0) {
|
while (chosen_item < 0) {
|
||||||
int key = WaitKey();
|
int key = WaitKey();
|
||||||
if (key == -1) { // WaitKey() timed out.
|
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()) {
|
if (WasTextEverVisible()) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
LOG(INFO) << "Timed out waiting for key input; rebooting.";
|
LOG(INFO) << "Timed out waiting for key input; rebooting.";
|
||||||
EndMenu();
|
EndMenu();
|
||||||
return static_cast<size_t>(-1);
|
return static_cast<size_t>(KeyError::TIMED_OUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -264,6 +264,10 @@ int TestableScreenRecoveryUI::KeyHandler(int key, bool) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int TestableScreenRecoveryUI::WaitKey() {
|
int TestableScreenRecoveryUI::WaitKey() {
|
||||||
|
if (IsKeyInterrupted()) {
|
||||||
|
return static_cast<int>(RecoveryUI::KeyError::INTERRUPTED);
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_LT(key_buffer_index_, key_buffer_.size());
|
CHECK_LT(key_buffer_index_, key_buffer_.size());
|
||||||
return static_cast<int>(key_buffer_[key_buffer_index_++]);
|
return static_cast<int>(key_buffer_[key_buffer_index_++]);
|
||||||
}
|
}
|
||||||
|
@ -391,7 +395,8 @@ TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut) {
|
||||||
ui_->SetKeyBuffer({
|
ui_->SetKeyBuffer({
|
||||||
KeyCode::TIMEOUT,
|
KeyCode::TIMEOUT,
|
||||||
});
|
});
|
||||||
ASSERT_EQ(static_cast<size_t>(-1), ui_->ShowMenu(HEADERS, ITEMS, 3, true, nullptr));
|
ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::TIMED_OUT),
|
||||||
|
ui_->ShowMenu(HEADERS, ITEMS, 3, true, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut_TextWasEverVisible) {
|
TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut_TextWasEverVisible) {
|
||||||
|
@ -412,6 +417,38 @@ TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut_TextWasEverVisible) {
|
||||||
std::placeholders::_1, std::placeholders::_2)));
|
std::placeholders::_1, std::placeholders::_2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ScreenRecoveryUITest, ShowMenuWithInterrupt) {
|
||||||
|
RETURN_IF_NO_GRAPHICS;
|
||||||
|
|
||||||
|
ASSERT_TRUE(ui_->Init(kTestLocale));
|
||||||
|
ui_->SetKeyBuffer({
|
||||||
|
KeyCode::UP,
|
||||||
|
KeyCode::DOWN,
|
||||||
|
KeyCode::UP,
|
||||||
|
KeyCode::DOWN,
|
||||||
|
KeyCode::ENTER,
|
||||||
|
});
|
||||||
|
|
||||||
|
ui_->InterruptKey();
|
||||||
|
ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED),
|
||||||
|
ui_->ShowMenu(HEADERS, ITEMS, 3, true,
|
||||||
|
std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
|
||||||
|
std::placeholders::_1, std::placeholders::_2)));
|
||||||
|
|
||||||
|
ui_->SetKeyBuffer({
|
||||||
|
KeyCode::UP,
|
||||||
|
KeyCode::UP,
|
||||||
|
KeyCode::NO_OP,
|
||||||
|
KeyCode::NO_OP,
|
||||||
|
KeyCode::UP,
|
||||||
|
KeyCode::ENTER,
|
||||||
|
});
|
||||||
|
ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED),
|
||||||
|
ui_->ShowMenu(HEADERS, ITEMS, 0, true,
|
||||||
|
std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
|
||||||
|
std::placeholders::_1, std::placeholders::_2)));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ScreenRecoveryUITest, LoadAnimation) {
|
TEST_F(ScreenRecoveryUITest, LoadAnimation) {
|
||||||
RETURN_IF_NO_GRAPHICS;
|
RETURN_IF_NO_GRAPHICS;
|
||||||
|
|
||||||
|
|
85
ui.cpp
85
ui.cpp
|
@ -58,6 +58,7 @@ RecoveryUI::RecoveryUI()
|
||||||
touch_screen_allowed_(false),
|
touch_screen_allowed_(false),
|
||||||
kTouchLowThreshold(RECOVERY_UI_TOUCH_LOW_THRESHOLD),
|
kTouchLowThreshold(RECOVERY_UI_TOUCH_LOW_THRESHOLD),
|
||||||
kTouchHighThreshold(RECOVERY_UI_TOUCH_HIGH_THRESHOLD),
|
kTouchHighThreshold(RECOVERY_UI_TOUCH_HIGH_THRESHOLD),
|
||||||
|
key_interrupted_(false),
|
||||||
key_queue_len(0),
|
key_queue_len(0),
|
||||||
key_last_down(-1),
|
key_last_down(-1),
|
||||||
key_long_press(false),
|
key_long_press(false),
|
||||||
|
@ -404,34 +405,69 @@ void RecoveryUI::EnqueueKey(int key_code) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecoveryUI::SetScreensaverState(ScreensaverState state) {
|
||||||
|
switch (state) {
|
||||||
|
case ScreensaverState::NORMAL:
|
||||||
|
if (android::base::WriteStringToFile(std::to_string(brightness_normal_value_),
|
||||||
|
brightness_file_)) {
|
||||||
|
screensaver_state_ = ScreensaverState::NORMAL;
|
||||||
|
LOG(INFO) << "Brightness: " << brightness_normal_value_ << " (" << brightness_normal_
|
||||||
|
<< "%)";
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Unable to set brightness to normal";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ScreensaverState::DIMMED:
|
||||||
|
if (android::base::WriteStringToFile(std::to_string(brightness_dimmed_value_),
|
||||||
|
brightness_file_)) {
|
||||||
|
LOG(INFO) << "Brightness: " << brightness_dimmed_value_ << " (" << brightness_dimmed_
|
||||||
|
<< "%)";
|
||||||
|
screensaver_state_ = ScreensaverState::DIMMED;
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Unable to set brightness to dim";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ScreensaverState::OFF:
|
||||||
|
if (android::base::WriteStringToFile("0", brightness_file_)) {
|
||||||
|
LOG(INFO) << "Brightness: 0 (off)";
|
||||||
|
screensaver_state_ = ScreensaverState::OFF;
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Unable to set brightness to off";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG(ERROR) << "Invalid screensaver state";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int RecoveryUI::WaitKey() {
|
int RecoveryUI::WaitKey() {
|
||||||
std::unique_lock<std::mutex> lk(key_queue_mutex);
|
std::unique_lock<std::mutex> lk(key_queue_mutex);
|
||||||
|
|
||||||
|
// Check for a saved key queue interruption.
|
||||||
|
if (key_interrupted_) {
|
||||||
|
SetScreensaverState(ScreensaverState::NORMAL);
|
||||||
|
return static_cast<int>(KeyError::INTERRUPTED);
|
||||||
|
}
|
||||||
|
|
||||||
// Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is
|
// Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is
|
||||||
// plugged in.
|
// plugged in.
|
||||||
do {
|
do {
|
||||||
std::cv_status rc = std::cv_status::no_timeout;
|
bool rc = key_queue_cond.wait_for(lk, std::chrono::seconds(UI_WAIT_KEY_TIMEOUT_SEC), [this] {
|
||||||
while (key_queue_len == 0 && rc != std::cv_status::timeout) {
|
return this->key_queue_len != 0 || key_interrupted_;
|
||||||
rc = key_queue_cond.wait_for(lk, std::chrono::seconds(UI_WAIT_KEY_TIMEOUT_SEC));
|
});
|
||||||
|
if (key_interrupted_) {
|
||||||
|
SetScreensaverState(ScreensaverState::NORMAL);
|
||||||
|
return static_cast<int>(KeyError::INTERRUPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (screensaver_state_ != ScreensaverState::DISABLED) {
|
if (screensaver_state_ != ScreensaverState::DISABLED) {
|
||||||
if (rc == std::cv_status::timeout) {
|
if (!rc) {
|
||||||
// Lower the brightness level: NORMAL -> DIMMED; DIMMED -> OFF.
|
// Lower the brightness level: NORMAL -> DIMMED; DIMMED -> OFF.
|
||||||
if (screensaver_state_ == ScreensaverState::NORMAL) {
|
if (screensaver_state_ == ScreensaverState::NORMAL) {
|
||||||
if (android::base::WriteStringToFile(std::to_string(brightness_dimmed_value_),
|
SetScreensaverState(ScreensaverState::DIMMED);
|
||||||
brightness_file_)) {
|
|
||||||
LOG(INFO) << "Brightness: " << brightness_dimmed_value_ << " (" << brightness_dimmed_
|
|
||||||
<< "%)";
|
|
||||||
screensaver_state_ = ScreensaverState::DIMMED;
|
|
||||||
}
|
|
||||||
} else if (screensaver_state_ == ScreensaverState::DIMMED) {
|
} else if (screensaver_state_ == ScreensaverState::DIMMED) {
|
||||||
if (android::base::WriteStringToFile("0", brightness_file_)) {
|
SetScreensaverState(ScreensaverState::OFF);
|
||||||
LOG(INFO) << "Brightness: 0 (off)";
|
|
||||||
screensaver_state_ = ScreensaverState::OFF;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (screensaver_state_ != ScreensaverState::NORMAL) {
|
} else {
|
||||||
// Drop the first key if it's changing from OFF to NORMAL.
|
// Drop the first key if it's changing from OFF to NORMAL.
|
||||||
if (screensaver_state_ == ScreensaverState::OFF) {
|
if (screensaver_state_ == ScreensaverState::OFF) {
|
||||||
if (key_queue_len > 0) {
|
if (key_queue_len > 0) {
|
||||||
|
@ -440,17 +476,12 @@ int RecoveryUI::WaitKey() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the brightness to normal.
|
// Reset the brightness to normal.
|
||||||
if (android::base::WriteStringToFile(std::to_string(brightness_normal_value_),
|
SetScreensaverState(ScreensaverState::NORMAL);
|
||||||
brightness_file_)) {
|
|
||||||
screensaver_state_ = ScreensaverState::NORMAL;
|
|
||||||
LOG(INFO) << "Brightness: " << brightness_normal_value_ << " (" << brightness_normal_
|
|
||||||
<< "%)";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (IsUsbConnected() && key_queue_len == 0);
|
} while (IsUsbConnected() && key_queue_len == 0);
|
||||||
|
|
||||||
int key = -1;
|
int key = static_cast<int>(KeyError::TIMED_OUT);
|
||||||
if (key_queue_len > 0) {
|
if (key_queue_len > 0) {
|
||||||
key = key_queue[0];
|
key = key_queue[0];
|
||||||
memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
|
memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
|
||||||
|
@ -458,6 +489,14 @@ int RecoveryUI::WaitKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecoveryUI::InterruptKey() {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lg(key_queue_mutex);
|
||||||
|
key_interrupted_ = true;
|
||||||
|
}
|
||||||
|
key_queue_cond.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
bool RecoveryUI::IsUsbConnected() {
|
bool RecoveryUI::IsUsbConnected() {
|
||||||
int fd = open("/sys/class/android_usb/android0/state", O_RDONLY);
|
int fd = open("/sys/class/android_usb/android0/state", O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
|
27
ui.h
27
ui.h
|
@ -51,6 +51,11 @@ class RecoveryUI {
|
||||||
IGNORE
|
IGNORE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class KeyError : int {
|
||||||
|
TIMED_OUT = -1,
|
||||||
|
INTERRUPTED = -2,
|
||||||
|
};
|
||||||
|
|
||||||
RecoveryUI();
|
RecoveryUI();
|
||||||
|
|
||||||
virtual ~RecoveryUI();
|
virtual ~RecoveryUI();
|
||||||
|
@ -99,9 +104,13 @@ class RecoveryUI {
|
||||||
|
|
||||||
// --- key handling ---
|
// --- key handling ---
|
||||||
|
|
||||||
// Waits for a key and return it. May return -1 after timeout.
|
// Waits for a key and return it. May return TIMED_OUT after timeout and
|
||||||
|
// KeyError::INTERRUPTED on a key interrupt.
|
||||||
virtual int WaitKey();
|
virtual int WaitKey();
|
||||||
|
|
||||||
|
// Wakes up the UI if it is waiting on key input, causing WaitKey to return KeyError::INTERRUPTED.
|
||||||
|
virtual void InterruptKey();
|
||||||
|
|
||||||
virtual bool IsKeyPressed(int key);
|
virtual bool IsKeyPressed(int key);
|
||||||
virtual bool IsLongPress();
|
virtual bool IsLongPress();
|
||||||
|
|
||||||
|
@ -147,11 +156,22 @@ class RecoveryUI {
|
||||||
// device-specific action, even without that being listed in the menu. Caller needs to handle
|
// device-specific action, even without that being listed in the menu. Caller needs to handle
|
||||||
// such a case accordingly (e.g. by calling Device::InvokeMenuItem() to process the action).
|
// such a case accordingly (e.g. by calling Device::InvokeMenuItem() to process the action).
|
||||||
// Returns a non-negative value (the chosen item number or device-specific action code), or
|
// Returns a non-negative value (the chosen item number or device-specific action code), or
|
||||||
// static_cast<size_t>(-1) if timed out waiting for input.
|
// static_cast<size_t>(TIMED_OUT) if timed out waiting for input or
|
||||||
|
// static_cast<size_t>(ERR_KEY_INTERTUPT) if interrupted, such as by InterruptKey().
|
||||||
virtual size_t ShowMenu(const std::vector<std::string>& headers,
|
virtual size_t ShowMenu(const std::vector<std::string>& headers,
|
||||||
const std::vector<std::string>& items, size_t initial_selection,
|
const std::vector<std::string>& items, size_t initial_selection,
|
||||||
bool menu_only, const std::function<int(int, bool)>& key_handler) = 0;
|
bool menu_only, const std::function<int(int, bool)>& key_handler) = 0;
|
||||||
|
|
||||||
|
// Resets the key interrupt status.
|
||||||
|
void ResetKeyInterruptStatus() {
|
||||||
|
key_interrupted_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the key interrupt status.
|
||||||
|
bool IsKeyInterrupted() const {
|
||||||
|
return key_interrupted_;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void EnqueueKey(int key_code);
|
void EnqueueKey(int key_code);
|
||||||
|
|
||||||
|
@ -187,10 +207,11 @@ class RecoveryUI {
|
||||||
bool IsUsbConnected();
|
bool IsUsbConnected();
|
||||||
|
|
||||||
bool InitScreensaver();
|
bool InitScreensaver();
|
||||||
|
void SetScreensaverState(ScreensaverState state);
|
||||||
// Key event input queue
|
// Key event input queue
|
||||||
std::mutex key_queue_mutex;
|
std::mutex key_queue_mutex;
|
||||||
std::condition_variable key_queue_cond;
|
std::condition_variable key_queue_cond;
|
||||||
|
bool key_interrupted_;
|
||||||
int key_queue[256], key_queue_len;
|
int key_queue[256], key_queue_len;
|
||||||
char key_pressed[KEY_MAX + 1]; // under key_queue_mutex
|
char key_pressed[KEY_MAX + 1]; // under key_queue_mutex
|
||||||
int key_last_down; // under key_queue_mutex
|
int key_last_down; // under key_queue_mutex
|
||||||
|
|
Loading…
Reference in a new issue