diff --git a/ui.cpp b/ui.cpp index a0f741e5..5efdc5a4 100644 --- a/ui.cpp +++ b/ui.cpp @@ -32,7 +32,11 @@ #include +#include +#include +#include #include +#include #include #include @@ -40,11 +44,15 @@ #include "roots.h" #include "device.h" -#define UI_WAIT_KEY_TIMEOUT_SEC 120 +static constexpr int UI_WAIT_KEY_TIMEOUT_SEC = 120; +static constexpr const char* BRIGHTNESS_FILE = "/sys/class/leds/lcd-backlight/brightness"; +static constexpr const char* MAX_BRIGHTNESS_FILE = "/sys/class/leds/lcd-backlight/max_brightness"; RecoveryUI::RecoveryUI() : locale_(""), rtl_locale_(false), + brightness_normal_(50), + brightness_dimmed_(25), key_queue_len(0), key_last_down(-1), key_long_press(false), @@ -54,7 +62,8 @@ RecoveryUI::RecoveryUI() last_key(-1), has_power_key(false), has_up_key(false), - has_down_key(false) { + has_down_key(false), + screensaver_state_(ScreensaverState::DISABLED) { pthread_mutex_init(&key_queue_mutex, nullptr); pthread_cond_init(&key_queue_cond, nullptr); memset(key_pressed, 0, sizeof(key_pressed)); @@ -80,6 +89,40 @@ static void* InputThreadLoop(void*) { return nullptr; } +bool RecoveryUI::InitScreensaver() { + // Disabled. + if (brightness_normal_ == 0 || brightness_dimmed_ > brightness_normal_) { + return false; + } + + // Set the initial brightness level based on the max brightness. Note that reading the initial + // value from BRIGHTNESS_FILE doesn't give the actual brightness value (bullhead, sailfish), so + // we don't have a good way to query the default value. + std::string content; + if (!android::base::ReadFileToString(MAX_BRIGHTNESS_FILE, &content)) { + LOG(WARNING) << "Failed to read max brightness: " << content; + return false; + } + + unsigned int max_value; + if (!android::base::ParseUint(android::base::Trim(content), &max_value)) { + LOG(WARNING) << "Failed to parse max brightness: " << content; + return false; + } + + brightness_normal_value_ = max_value * brightness_normal_ / 100.0; + brightness_dimmed_value_ = max_value * brightness_dimmed_ / 100.0; + if (!android::base::WriteStringToFile(std::to_string(brightness_normal_value_), + BRIGHTNESS_FILE)) { + PLOG(WARNING) << "Failed to set brightness"; + return false; + } + + LOG(INFO) << "Brightness: " << brightness_normal_value_ << " (" << brightness_normal_ << "%)"; + screensaver_state_ = ScreensaverState::NORMAL; + return true; +} + bool RecoveryUI::Init(const std::string& locale) { // Set up the locale info. SetLocale(locale); @@ -88,6 +131,10 @@ bool RecoveryUI::Init(const std::string& locale) { ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1)); + if (!InitScreensaver()) { + LOG(INFO) << "Screensaver disabled"; + } + pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr); return true; } @@ -220,31 +267,65 @@ void RecoveryUI::EnqueueKey(int key_code) { } int RecoveryUI::WaitKey() { - pthread_mutex_lock(&key_queue_mutex); + pthread_mutex_lock(&key_queue_mutex); - // Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is - // plugged in. - do { - struct timeval now; - struct timespec timeout; - gettimeofday(&now, nullptr); - timeout.tv_sec = now.tv_sec; - timeout.tv_nsec = now.tv_usec * 1000; - timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC; + // Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is + // plugged in. + do { + struct timeval now; + struct timespec timeout; + gettimeofday(&now, nullptr); + timeout.tv_sec = now.tv_sec; + timeout.tv_nsec = now.tv_usec * 1000; + timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC; - int rc = 0; - while (key_queue_len == 0 && rc != ETIMEDOUT) { - rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, &timeout); - } - } while (IsUsbConnected() && key_queue_len == 0); - - int key = -1; - if (key_queue_len > 0) { - key = key_queue[0]; - memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len); + int rc = 0; + while (key_queue_len == 0 && rc != ETIMEDOUT) { + rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, &timeout); } - pthread_mutex_unlock(&key_queue_mutex); - return key; + + if (screensaver_state_ != ScreensaverState::DISABLED) { + if (rc == ETIMEDOUT) { + // Lower the brightness level: NORMAL -> DIMMED; DIMMED -> OFF. + if (screensaver_state_ == ScreensaverState::NORMAL) { + 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 if (screensaver_state_ == ScreensaverState::DIMMED) { + if (android::base::WriteStringToFile("0", BRIGHTNESS_FILE)) { + LOG(INFO) << "Brightness: 0 (off)"; + screensaver_state_ = ScreensaverState::OFF; + } + } + } 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); + } + } + + // Reset the brightness to 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_ + << "%)"; + } + } + } + } while (IsUsbConnected() && key_queue_len == 0); + + int key = -1; + if (key_queue_len > 0) { + key = key_queue[0]; + memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len); + } + pthread_mutex_unlock(&key_queue_mutex); + return key; } bool RecoveryUI::IsUsbConnected() { @@ -330,7 +411,7 @@ RecoveryUI::KeyAction RecoveryUI::CheckKey(int key, bool is_long_press) { } last_key = key; - return IsTextVisible() ? ENQUEUE : IGNORE; + return (IsTextVisible() || screensaver_state_ == ScreensaverState::OFF) ? ENQUEUE : IGNORE; } void RecoveryUI::KeyLongPress(int) { diff --git a/ui.h b/ui.h index 53ce0602..823eb657 100644 --- a/ui.h +++ b/ui.h @@ -130,6 +130,13 @@ class RecoveryUI { std::string locale_; bool rtl_locale_; + // 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 be configured via subclassing. Setting brightness_normal_ to 0 to disable + // screensaver. + unsigned int brightness_normal_; + unsigned int brightness_dimmed_; + private: // Key event input queue pthread_mutex_t key_queue_mutex; @@ -167,6 +174,14 @@ class RecoveryUI { void time_key(int key_code, int count); void SetLocale(const std::string&); + + enum class ScreensaverState { DISABLED, NORMAL, DIMMED, OFF }; + ScreensaverState screensaver_state_; + // The following two contain the absolute values computed from brightness_normal_ and + // brightness_dimmed_ respectively. + unsigned int brightness_normal_value_; + unsigned int brightness_dimmed_value_; + bool InitScreensaver(); }; #endif // RECOVERY_UI_H