Loading fastboot/fastboot.cpp +28 −4 Original line number Diff line number Diff line Loading @@ -36,10 +36,8 @@ static const std::vector<std::pair<std::string, Device::BuiltinAction>> kFastboo { "Power off", Device::SHUTDOWN_FROM_FASTBOOT }, }; Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) { RecoveryUI* ui = device->GetUI(); std::vector<std::string> title_lines = { "Android Fastboot" }; void FillDefaultFastbootLines(std::vector<std::string>& title_lines) { title_lines.push_back("Android Fastboot"); title_lines.push_back("Product name - " + android::base::GetProperty("ro.product.device", "")); title_lines.push_back("Bootloader version - " + android::base::GetProperty("ro.bootloader", "")); title_lines.push_back("Baseband version - " + Loading @@ -48,6 +46,32 @@ Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::strin title_lines.push_back(std::string("Secure boot - ") + ((android::base::GetProperty("ro.secure", "") == "1") ? "yes" : "no")); title_lines.push_back("HW version - " + android::base::GetProperty("ro.revision", "")); } void FillWearableFastbootLines(std::vector<std::string>& title_lines) { title_lines.push_back("Android Fastboot"); title_lines.push_back(android::base::GetProperty("ro.product.device", "") + " - " + android::base::GetProperty("ro.revision", "")); title_lines.push_back(android::base::GetProperty("ro.bootloader", "")); const size_t max_baseband_len = 24; const std::string& baseband = android::base::GetProperty("ro.build.expect.baseband", ""); title_lines.push_back(baseband.length() > max_baseband_len ? baseband.substr(0, max_baseband_len - 3) + "..." : baseband); title_lines.push_back("Serial #: " + android::base::GetProperty("ro.serialno", "")); } Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) { RecoveryUI* ui = device->GetUI(); std::vector<std::string> title_lines; if (ui->IsWearable()) { FillWearableFastbootLines(title_lines); } else { FillDefaultFastbootLines(title_lines); } ui->ResetKeyInterruptStatus(); ui->SetTitle(title_lines); Loading recovery_ui/include/recovery_ui/screen_ui.h +2 −1 Original line number Diff line number Diff line Loading @@ -309,7 +309,7 @@ class ScreenRecoveryUI : public RecoveryUI, public DrawInterface { void PutChar(char); void ClearText(); void LoadAnimation(); virtual void LoadAnimation(); std::unique_ptr<GRSurface> LoadBitmap(const std::string& filename); std::unique_ptr<GRSurface> LoadLocalizedBitmap(const std::string& filename); Loading Loading @@ -416,6 +416,7 @@ class ScreenRecoveryUI : public RecoveryUI, public DrawInterface { // Display the background texts for "erasing", "error", "no_command" and "installing" for the // selected locale. void SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries, size_t sel); }; #endif // RECOVERY_UI_H recovery_ui/include/recovery_ui/ui.h +4 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,10 @@ class RecoveryUI { const std::vector<std::string>& backup_headers, const std::vector<std::string>& backup_items, const std::function<int(int, bool)>& key_handler) = 0; virtual bool IsWearable() { return false; } // Set whether or not the fastbootd logo is displayed. void SetEnableFastbootdLogo(bool enable) { fastbootd_logo_enabled_ = enable; Loading recovery_ui/include/recovery_ui/wear_ui.h +17 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,10 @@ class WearRecoveryUI : public ScreenRecoveryUI { void SetStage(int current, int max) override; protected: // curved progress bar frames for round screens std::vector<std::unique_ptr<GRSurface>> progress_frames_; std::vector<std::unique_ptr<GRSurface>> rtl_progress_frames_; // progress bar vertical position, it's centered horizontally const int progress_bar_baseline_; Loading @@ -36,17 +40,30 @@ class WearRecoveryUI : public ScreenRecoveryUI { // Recovery, build id and etc) and the bottom lines that may otherwise go out of the screen. const int menu_unusable_rows_; const bool is_screen_circle_; std::unique_ptr<Menu> CreateMenu(const std::vector<std::string>& text_headers, const std::vector<std::string>& text_items, size_t initial_selection) const override; int GetProgressBaseline() const override; int GetTextBaseline() const override; void update_progress_locked() override; void LoadAnimation() override; bool IsWearable() override; void SetProgress(float fraction) override; private: void draw_background_locked() override; void draw_screen_locked() override; void draw_circle_foreground_locked(); size_t GetProgressFrameIndex(float fraction) const; }; #endif // RECOVERY_WEAR_UI_H recovery_ui/wear_ui.cpp +140 −22 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include "otautil/paths.h" #include "recovery_ui/wear_ui.h" #include <string.h> Loading @@ -23,24 +24,25 @@ #include <android-base/properties.h> #include <android-base/strings.h> #include <minui/minui.h> constexpr int kDefaultProgressBarBaseline = 259; constexpr int kDefaultMenuUnusableRows = 9; constexpr int kProgressBarVerticalOffsetDp = 72; constexpr bool kDefaultIsScreenCircle = true; WearRecoveryUI::WearRecoveryUI() : ScreenRecoveryUI(true), progress_bar_baseline_(android::base::GetIntProperty("ro.recovery.ui.progress_bar_baseline", kDefaultProgressBarBaseline)), menu_unusable_rows_(android::base::GetIntProperty("ro.recovery.ui.menu_unusable_rows", kDefaultMenuUnusableRows)) { kDefaultMenuUnusableRows)), is_screen_circle_(android::base::GetBoolProperty("ro.recovery.ui.is_screen_circle", kDefaultIsScreenCircle)) { // TODO: menu_unusable_rows_ should be computed based on the lines in draw_screen_locked(). touch_screen_allowed_ = true; } int WearRecoveryUI::GetProgressBaseline() const { return progress_bar_baseline_; SetEnableFastbootdLogo(false); // logo not required on Wear } // Draw background frame on the screen. Does not flip pages. Loading @@ -51,30 +53,38 @@ void WearRecoveryUI::draw_background_locked() { gr_color(0, 0, 0, 255); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); if (current_icon_ != NONE) { if (current_icon_ == ERROR) { const auto& frame = GetCurrentFrame(); int frame_width = gr_get_width(frame); int frame_height = gr_get_height(frame); int frame_x = (gr_fb_width() - frame_width) / 2; int frame_y = (gr_fb_height() - frame_height) / 2; gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y); } // Draw recovery text on screen above progress bar. if (current_icon_ != NONE) { // Draw recovery text on screen centered const auto& text = GetCurrentText(); int text_x = (ScreenWidth() - gr_get_width(text)) / 2; int text_y = GetProgressBaseline() - gr_get_height(text) - 10; int text_y = (ScreenHeight() - gr_get_height(text)) / 2; gr_color(255, 255, 255, 255); gr_texticon(text_x, text_y, text); } } void WearRecoveryUI::draw_screen_locked() { draw_background_locked(); if (!show_text) { draw_foreground_locked(); draw_background_locked(); if (is_screen_circle_) { draw_circle_foreground_locked(); } else { draw_foreground_locked(); } return; } SetColor(UIElement::TEXT_FILL); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); gr_clear(); // clang-format off static std::vector<std::string> SWIPE_HELP = { Loading @@ -85,6 +95,110 @@ void WearRecoveryUI::draw_screen_locked() { // clang-format on draw_menu_and_text_buffer_locked(SWIPE_HELP); } void WearRecoveryUI::draw_circle_foreground_locked() { if (current_icon_ != NONE) { const auto& frame = GetCurrentFrame(); int frame_width = gr_get_width(frame); int frame_height = gr_get_height(frame); int frame_x = (ScreenWidth() - frame_width) / 2; int frame_y = GetAnimationBaseline(); DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y); } if (progressBarType == DETERMINATE) { const auto& first_progress_frame = rtl_locale_ ? rtl_progress_frames_[0].get() :progress_frames_[0].get(); int width = gr_get_width(first_progress_frame); int height = gr_get_height(first_progress_frame); int progress_x = (ScreenWidth() - width) / 2; int progress_y = GetProgressBaseline(); const auto index = GetProgressFrameIndex(progress); const auto& frame = rtl_locale_ ? rtl_progress_frames_[index].get() : progress_frames_[index].get(); DrawSurface(frame, 0, 0, width, height, progress_x, progress_y); } } void WearRecoveryUI::LoadAnimation() { ScreenRecoveryUI::LoadAnimation(); std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(Paths::Get().resource_dir().c_str()), closedir); dirent* de; std::vector<std::string> progress_frame_names; std::vector<std::string> rtl_progress_frame_names; if(dir.get() == nullptr) abort(); while ((de = readdir(dir.get())) != nullptr) { int value, num_chars; if (sscanf(de->d_name, "progress%d%n.png", &value, &num_chars) == 1) { progress_frame_names.emplace_back(de->d_name, num_chars); } else if (sscanf(de->d_name, "rtl_progress%d%n.png", &value, &num_chars) == 1) { rtl_progress_frame_names.emplace_back(de->d_name, num_chars); } } size_t progress_frames = progress_frame_names.size(); size_t rtl_progress_frames = rtl_progress_frame_names.size(); // You must have an animation. if (progress_frames == 0 || rtl_progress_frames == 0) abort(); std::sort(progress_frame_names.begin(), progress_frame_names.end()); std::sort(rtl_progress_frame_names.begin(), rtl_progress_frame_names.end()); progress_frames_.clear(); progress_frames_.reserve(progress_frames); for (const auto& frame_name : progress_frame_names) { progress_frames_.emplace_back(LoadBitmap(frame_name)); } rtl_progress_frames_.clear(); rtl_progress_frames_.reserve(rtl_progress_frames); for (const auto& frame_name : rtl_progress_frame_names) { rtl_progress_frames_.emplace_back(LoadBitmap(frame_name)); } } void WearRecoveryUI::SetProgress(float fraction) { if (is_screen_circle_) { std::lock_guard<std::mutex> lg(updateMutex); if (fraction < 0.0) fraction = 0.0; if (fraction > 1.0) fraction = 1.0; if (progressBarType == DETERMINATE && fraction > progress) { // Skip updates that aren't visibly different. if (GetProgressFrameIndex(fraction) != GetProgressFrameIndex(progress)) { // circular display progress = fraction; update_progress_locked(); } } } else { // rectangular display ScreenRecoveryUI::SetProgress(fraction); } } int WearRecoveryUI::GetProgressBaseline() const { int progress_height = gr_get_height(progress_frames_[0].get()); return (ScreenHeight() - progress_height) / 2 + PixelsFromDp(kProgressBarVerticalOffsetDp); } int WearRecoveryUI::GetTextBaseline() const { if (is_screen_circle_) { return GetProgressBaseline() - PixelsFromDp(kProgressBarVerticalOffsetDp) - gr_get_height(installing_text_.get()); } else { return ScreenRecoveryUI::GetTextBaseline(); } } size_t WearRecoveryUI::GetProgressFrameIndex(float fraction) const { return static_cast<size_t>(fraction * (progress_frames_.size() - 1)); } // TODO merge drawing routines with screen_ui Loading @@ -93,6 +207,10 @@ void WearRecoveryUI::update_progress_locked() { gr_flip(); } bool WearRecoveryUI::IsWearable() { return true; } void WearRecoveryUI::SetStage(int /* current */, int /* max */) {} std::unique_ptr<Menu> WearRecoveryUI::CreateMenu(const std::vector<std::string>& text_headers, Loading Loading
fastboot/fastboot.cpp +28 −4 Original line number Diff line number Diff line Loading @@ -36,10 +36,8 @@ static const std::vector<std::pair<std::string, Device::BuiltinAction>> kFastboo { "Power off", Device::SHUTDOWN_FROM_FASTBOOT }, }; Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) { RecoveryUI* ui = device->GetUI(); std::vector<std::string> title_lines = { "Android Fastboot" }; void FillDefaultFastbootLines(std::vector<std::string>& title_lines) { title_lines.push_back("Android Fastboot"); title_lines.push_back("Product name - " + android::base::GetProperty("ro.product.device", "")); title_lines.push_back("Bootloader version - " + android::base::GetProperty("ro.bootloader", "")); title_lines.push_back("Baseband version - " + Loading @@ -48,6 +46,32 @@ Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::strin title_lines.push_back(std::string("Secure boot - ") + ((android::base::GetProperty("ro.secure", "") == "1") ? "yes" : "no")); title_lines.push_back("HW version - " + android::base::GetProperty("ro.revision", "")); } void FillWearableFastbootLines(std::vector<std::string>& title_lines) { title_lines.push_back("Android Fastboot"); title_lines.push_back(android::base::GetProperty("ro.product.device", "") + " - " + android::base::GetProperty("ro.revision", "")); title_lines.push_back(android::base::GetProperty("ro.bootloader", "")); const size_t max_baseband_len = 24; const std::string& baseband = android::base::GetProperty("ro.build.expect.baseband", ""); title_lines.push_back(baseband.length() > max_baseband_len ? baseband.substr(0, max_baseband_len - 3) + "..." : baseband); title_lines.push_back("Serial #: " + android::base::GetProperty("ro.serialno", "")); } Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) { RecoveryUI* ui = device->GetUI(); std::vector<std::string> title_lines; if (ui->IsWearable()) { FillWearableFastbootLines(title_lines); } else { FillDefaultFastbootLines(title_lines); } ui->ResetKeyInterruptStatus(); ui->SetTitle(title_lines); Loading
recovery_ui/include/recovery_ui/screen_ui.h +2 −1 Original line number Diff line number Diff line Loading @@ -309,7 +309,7 @@ class ScreenRecoveryUI : public RecoveryUI, public DrawInterface { void PutChar(char); void ClearText(); void LoadAnimation(); virtual void LoadAnimation(); std::unique_ptr<GRSurface> LoadBitmap(const std::string& filename); std::unique_ptr<GRSurface> LoadLocalizedBitmap(const std::string& filename); Loading Loading @@ -416,6 +416,7 @@ class ScreenRecoveryUI : public RecoveryUI, public DrawInterface { // Display the background texts for "erasing", "error", "no_command" and "installing" for the // selected locale. void SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries, size_t sel); }; #endif // RECOVERY_UI_H
recovery_ui/include/recovery_ui/ui.h +4 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,10 @@ class RecoveryUI { const std::vector<std::string>& backup_headers, const std::vector<std::string>& backup_items, const std::function<int(int, bool)>& key_handler) = 0; virtual bool IsWearable() { return false; } // Set whether or not the fastbootd logo is displayed. void SetEnableFastbootdLogo(bool enable) { fastbootd_logo_enabled_ = enable; Loading
recovery_ui/include/recovery_ui/wear_ui.h +17 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,10 @@ class WearRecoveryUI : public ScreenRecoveryUI { void SetStage(int current, int max) override; protected: // curved progress bar frames for round screens std::vector<std::unique_ptr<GRSurface>> progress_frames_; std::vector<std::unique_ptr<GRSurface>> rtl_progress_frames_; // progress bar vertical position, it's centered horizontally const int progress_bar_baseline_; Loading @@ -36,17 +40,30 @@ class WearRecoveryUI : public ScreenRecoveryUI { // Recovery, build id and etc) and the bottom lines that may otherwise go out of the screen. const int menu_unusable_rows_; const bool is_screen_circle_; std::unique_ptr<Menu> CreateMenu(const std::vector<std::string>& text_headers, const std::vector<std::string>& text_items, size_t initial_selection) const override; int GetProgressBaseline() const override; int GetTextBaseline() const override; void update_progress_locked() override; void LoadAnimation() override; bool IsWearable() override; void SetProgress(float fraction) override; private: void draw_background_locked() override; void draw_screen_locked() override; void draw_circle_foreground_locked(); size_t GetProgressFrameIndex(float fraction) const; }; #endif // RECOVERY_WEAR_UI_H
recovery_ui/wear_ui.cpp +140 −22 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include "otautil/paths.h" #include "recovery_ui/wear_ui.h" #include <string.h> Loading @@ -23,24 +24,25 @@ #include <android-base/properties.h> #include <android-base/strings.h> #include <minui/minui.h> constexpr int kDefaultProgressBarBaseline = 259; constexpr int kDefaultMenuUnusableRows = 9; constexpr int kProgressBarVerticalOffsetDp = 72; constexpr bool kDefaultIsScreenCircle = true; WearRecoveryUI::WearRecoveryUI() : ScreenRecoveryUI(true), progress_bar_baseline_(android::base::GetIntProperty("ro.recovery.ui.progress_bar_baseline", kDefaultProgressBarBaseline)), menu_unusable_rows_(android::base::GetIntProperty("ro.recovery.ui.menu_unusable_rows", kDefaultMenuUnusableRows)) { kDefaultMenuUnusableRows)), is_screen_circle_(android::base::GetBoolProperty("ro.recovery.ui.is_screen_circle", kDefaultIsScreenCircle)) { // TODO: menu_unusable_rows_ should be computed based on the lines in draw_screen_locked(). touch_screen_allowed_ = true; } int WearRecoveryUI::GetProgressBaseline() const { return progress_bar_baseline_; SetEnableFastbootdLogo(false); // logo not required on Wear } // Draw background frame on the screen. Does not flip pages. Loading @@ -51,30 +53,38 @@ void WearRecoveryUI::draw_background_locked() { gr_color(0, 0, 0, 255); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); if (current_icon_ != NONE) { if (current_icon_ == ERROR) { const auto& frame = GetCurrentFrame(); int frame_width = gr_get_width(frame); int frame_height = gr_get_height(frame); int frame_x = (gr_fb_width() - frame_width) / 2; int frame_y = (gr_fb_height() - frame_height) / 2; gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y); } // Draw recovery text on screen above progress bar. if (current_icon_ != NONE) { // Draw recovery text on screen centered const auto& text = GetCurrentText(); int text_x = (ScreenWidth() - gr_get_width(text)) / 2; int text_y = GetProgressBaseline() - gr_get_height(text) - 10; int text_y = (ScreenHeight() - gr_get_height(text)) / 2; gr_color(255, 255, 255, 255); gr_texticon(text_x, text_y, text); } } void WearRecoveryUI::draw_screen_locked() { draw_background_locked(); if (!show_text) { draw_foreground_locked(); draw_background_locked(); if (is_screen_circle_) { draw_circle_foreground_locked(); } else { draw_foreground_locked(); } return; } SetColor(UIElement::TEXT_FILL); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); gr_clear(); // clang-format off static std::vector<std::string> SWIPE_HELP = { Loading @@ -85,6 +95,110 @@ void WearRecoveryUI::draw_screen_locked() { // clang-format on draw_menu_and_text_buffer_locked(SWIPE_HELP); } void WearRecoveryUI::draw_circle_foreground_locked() { if (current_icon_ != NONE) { const auto& frame = GetCurrentFrame(); int frame_width = gr_get_width(frame); int frame_height = gr_get_height(frame); int frame_x = (ScreenWidth() - frame_width) / 2; int frame_y = GetAnimationBaseline(); DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y); } if (progressBarType == DETERMINATE) { const auto& first_progress_frame = rtl_locale_ ? rtl_progress_frames_[0].get() :progress_frames_[0].get(); int width = gr_get_width(first_progress_frame); int height = gr_get_height(first_progress_frame); int progress_x = (ScreenWidth() - width) / 2; int progress_y = GetProgressBaseline(); const auto index = GetProgressFrameIndex(progress); const auto& frame = rtl_locale_ ? rtl_progress_frames_[index].get() : progress_frames_[index].get(); DrawSurface(frame, 0, 0, width, height, progress_x, progress_y); } } void WearRecoveryUI::LoadAnimation() { ScreenRecoveryUI::LoadAnimation(); std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(Paths::Get().resource_dir().c_str()), closedir); dirent* de; std::vector<std::string> progress_frame_names; std::vector<std::string> rtl_progress_frame_names; if(dir.get() == nullptr) abort(); while ((de = readdir(dir.get())) != nullptr) { int value, num_chars; if (sscanf(de->d_name, "progress%d%n.png", &value, &num_chars) == 1) { progress_frame_names.emplace_back(de->d_name, num_chars); } else if (sscanf(de->d_name, "rtl_progress%d%n.png", &value, &num_chars) == 1) { rtl_progress_frame_names.emplace_back(de->d_name, num_chars); } } size_t progress_frames = progress_frame_names.size(); size_t rtl_progress_frames = rtl_progress_frame_names.size(); // You must have an animation. if (progress_frames == 0 || rtl_progress_frames == 0) abort(); std::sort(progress_frame_names.begin(), progress_frame_names.end()); std::sort(rtl_progress_frame_names.begin(), rtl_progress_frame_names.end()); progress_frames_.clear(); progress_frames_.reserve(progress_frames); for (const auto& frame_name : progress_frame_names) { progress_frames_.emplace_back(LoadBitmap(frame_name)); } rtl_progress_frames_.clear(); rtl_progress_frames_.reserve(rtl_progress_frames); for (const auto& frame_name : rtl_progress_frame_names) { rtl_progress_frames_.emplace_back(LoadBitmap(frame_name)); } } void WearRecoveryUI::SetProgress(float fraction) { if (is_screen_circle_) { std::lock_guard<std::mutex> lg(updateMutex); if (fraction < 0.0) fraction = 0.0; if (fraction > 1.0) fraction = 1.0; if (progressBarType == DETERMINATE && fraction > progress) { // Skip updates that aren't visibly different. if (GetProgressFrameIndex(fraction) != GetProgressFrameIndex(progress)) { // circular display progress = fraction; update_progress_locked(); } } } else { // rectangular display ScreenRecoveryUI::SetProgress(fraction); } } int WearRecoveryUI::GetProgressBaseline() const { int progress_height = gr_get_height(progress_frames_[0].get()); return (ScreenHeight() - progress_height) / 2 + PixelsFromDp(kProgressBarVerticalOffsetDp); } int WearRecoveryUI::GetTextBaseline() const { if (is_screen_circle_) { return GetProgressBaseline() - PixelsFromDp(kProgressBarVerticalOffsetDp) - gr_get_height(installing_text_.get()); } else { return ScreenRecoveryUI::GetTextBaseline(); } } size_t WearRecoveryUI::GetProgressFrameIndex(float fraction) const { return static_cast<size_t>(fraction * (progress_frames_.size() - 1)); } // TODO merge drawing routines with screen_ui Loading @@ -93,6 +207,10 @@ void WearRecoveryUI::update_progress_locked() { gr_flip(); } bool WearRecoveryUI::IsWearable() { return true; } void WearRecoveryUI::SetStage(int /* current */, int /* max */) {} std::unique_ptr<Menu> WearRecoveryUI::CreateMenu(const std::vector<std::string>& text_headers, Loading