Wear Recovery UI: Adjust for round screens
Change-Id: Ice4b8d4fcdc37ee1ca44ef195cb870b141862f08
This commit is contained in:
parent
1551e6a0a4
commit
ebc02271ec
6 changed files with 228 additions and 28 deletions
|
@ -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 - " +
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "otautil/paths.h"
|
||||
#include "recovery_ui/wear_ui.h"
|
||||
|
||||
#include <string.h>
|
||||
|
@ -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.
|
||||
|
@ -51,40 +53,152 @@ 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();
|
||||
} else {
|
||||
SetColor(UIElement::TEXT_FILL);
|
||||
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
|
||||
|
||||
// clang-format off
|
||||
static std::vector<std::string> SWIPE_HELP = {
|
||||
"Swipe up/down to move.",
|
||||
"Swipe left/right to select.",
|
||||
"",
|
||||
};
|
||||
// clang-format on
|
||||
draw_menu_and_text_buffer_locked(SWIPE_HELP);
|
||||
draw_background_locked();
|
||||
if (is_screen_circle_) {
|
||||
draw_circle_foreground_locked();
|
||||
} else {
|
||||
draw_foreground_locked();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SetColor(UIElement::TEXT_FILL);
|
||||
gr_clear();
|
||||
|
||||
// clang-format off
|
||||
static std::vector<std::string> SWIPE_HELP = {
|
||||
"Swipe up/down to move.",
|
||||
"Swipe left/right to select.",
|
||||
"",
|
||||
};
|
||||
// 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
|
||||
|
@ -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,
|
||||
|
|
36
tools/image_generator/draw-progress.sh
Normal file
36
tools/image_generator/draw-progress.sh
Normal file
|
@ -0,0 +1,36 @@
|
|||
#!/bin/bash
|
||||
|
||||
# arc central angle in degrees
|
||||
arc_size="64.5"
|
||||
|
||||
arc_start=$(bc -l <<< "90 - $arc_size / 2")
|
||||
arc_end=$(bc -l <<< "90 + $arc_size / 2")
|
||||
|
||||
N=100
|
||||
for ((i=0; i < $N; i++)); do
|
||||
progress=$(bc -l <<< "$i / ($N - 1)")
|
||||
fg_arc_start=$(bc -l <<< "$arc_end - $progress * $arc_size")
|
||||
|
||||
filename="progress$(printf "%02d" $i).png"
|
||||
echo "-- Writing file: $filename"
|
||||
|
||||
convert -size 400x400 xc:black \
|
||||
-draw "stroke-linecap round stroke-width 8 \
|
||||
stroke gray ellipse 200,200 100,100 $arc_start,$arc_end \
|
||||
stroke white ellipse 200,200 100,100 $fg_arc_start,$arc_end" "$filename"
|
||||
|
||||
echo "-- Writing file: rtl_$filename"
|
||||
convert -size 400x400 xc:black \
|
||||
-draw "stroke-linecap round stroke-width 8 \
|
||||
stroke gray ellipse 200,200 100,100 $arc_start,$arc_end \
|
||||
stroke white ellipse 200,200 100,100 $fg_arc_start,$arc_end" "rtl_$filename"
|
||||
|
||||
mogrify -crop 120x30+140+280 "$filename"
|
||||
mogrify -crop 120x30+140+280 "rtl_$filename"
|
||||
|
||||
# Use color format recovery can use
|
||||
mogrify -define png:format=png24 -type TrueColor "$filename"
|
||||
mogrify -define png:format=png24 -type TrueColor "rtl_$filename"
|
||||
|
||||
mogrify -flop "rtl_$filename"
|
||||
done
|
Loading…
Reference in a new issue